C言語関係掲示板

過去ログ

No.571.string.hなしでstrcmp関数が動作したのはなぜ?

[戻る] [ホームページ]
No.5235

string.hなしでstrcmp関数などが入ったプログラムが動作したのはなぜ?
投稿者---K.I(2003/02/17 23:35:26)


はじめまして。
C言語でCGIプログラムを書いているのですが、このたび、
strcmpやstrstrを使っているにも関わらず、うっかりstring.hを
インクルードするのを忘れてコンパイルしてしまいました。
ところが、コンパイルが通ってしまい、なおかつ問題なく動作
しています。
普通は、string.hが必要だと思うのですが、
環境によって異なる定義がされていたりすることがあるのでしょうか。
環境は、FreeBSD 4.4です。

No.5237

Re:string.hなしでstrcmp関数などが入ったプログラムが動作したのはなぜ?
投稿者---a"(2003/02/17 23:59:46)


たまたまだとおもいます。
ちなみにvc++の話しか知りませんけど。
C言語はかってにint型の返す外部関数とみなすwarningがでます。
そしてc++ではエラーが出ます.



No.5243

Re:string.hなしでstrcmp関数などが入ったプログラムが動作したのはなぜ?
投稿者---hara(2003/02/18 03:49:32)


それらがビルトイン関数だからです。コンパイラのビルトイン関数は
ヘッダファイルをインクルードしなくても使えるようです。

私もあんまり詳しくはないのですが、gcc に限ればビルトイン関数は、
_exit, abort, abs, alloca, cos, exit, fabs, labs, memcmp, memcpy,
sin, sqrt, strcmp, strcpy, strlen などがそうらしいです。
マニュアルの -fno-builtin オプションに説明があります。

No.5260

gccのbuilt-inとは?
投稿者---麗(2003/02/19 10:45:07)


gccがbuilt-in関数とみなしている関数については
プロトタイプ宣言を書かなくても良いということでしょうか?

それともgcc内部にbuilt-in関数のマシンコードを持っていて
それをリンク時に展開しているということなのでしょうか?

…libcは要らない?

No.5279

Re:gccのbuilt-inとは?
投稿者---hara(2003/02/20 11:19:43)


先は、とおりすがりのつもりで書き込んだのですが、ちょっと調べてみました。
私自身あんまり分かってないのにレスするのも何ですが (^^;。。
※C 言語というよりかなりコンパイラの話で、掲示板の趣旨と違いすぎる
※と判断されたら削除してくださってもかまいません。>管理人様

>gccがbuilt-in関数とみなしている関数については
>プロトタイプ宣言を書かなくても良いということでしょうか?

ビルトイン関数が有効になっていれば、宣言しなくてもコンパイルできます。
ビルトイン関数のプロトタイプ宣言を書かなくてもコンパイルが通るのは、
gcc の中ですでに宣言されるから、みたいです。
gcc のソースアーカイブの c-decl.c (strcpy の部分を抜粋)
  string_ftype_ptr_ptr          /* strcpy prototype */
= build_function_type (string_type_node,
tree_cons (NULL_TREE, string_type_node,
tree_cons (NULL_TREE,
const_string_type_node,
endlink)));
ところが、gcc のバージョンやオプションの組み合わせなどによっては、
ビルトイン関数が無効になることがあります (たとえば -fno-builtin)。
こういった場合は、gcc の中でプロトタイプ宣言がなされません。
ある関数 (gcc ソースアーカイブ com.c 参照) を使って宣言の有無を
切替えているようです。
まあコンパイラ依存のソースになるので、プロトタイプ宣言はあるべきだと思います。

>それともgcc内部にbuilt-in関数のマシンコードを持っていて
>それをリンク時に展開しているということなのでしょうか?

うーん、どうなんでしょう。この辺りは分かりません。

>…libcは要らない?

ビルトイン関数だからといっても外部リンケージされることもあります。
たとえば、インライン展開や別コード置換ができないとき、-O オプションが
指定されていないときです (-O0 も同様)。その場合は普通に関数を呼びますが
たいていその関数は libc にあるため、通常は libc が必要になります。

しかし、指摘されたように要らないときもあります。インライン展開されたり
別コード置換したりした結果、libc (標準ライブラリ関数) を使わないときです。
もちろん、すべてのオブジェクトファイルのシンボルが libc を使わずに
解決できなければなりませんけど。


No.5281

Re:gccのbuilt-inとは?
投稿者---麗(2003/02/20 12:52:52)


ご回答ありがとうございます。
gccの中を追いかけるなんて…凄いです。
本当は技術的なことを含んだ、もう少しマトモなレスをつけたかったのですが
いかんせん私の勉強不足ゆえお礼で精一杯です。
いろいろ、教えていただいてありがとうございました。

No.5259

string.hなしでstrcmp関数などが入ったプログラムが動作したのはなぜ?
投稿者---K.I(2003/02/18 23:30:55)


下記の件、回答ありがとうございました。

>はじめまして。
>C言語でCGIプログラムを書いているのですが、このたび、
>strcmpやstrstrを使っているにも関わらず、うっかりstring.hを
>インクルードするのを忘れてコンパイルしてしまいました。
>ところが、コンパイルが通ってしまい、なおかつ問題なく動作
>しています。
>普通は、string.hが必要だと思うのですが、
>環境によって異なる定義がされていたりすることがあるのでしょうか。
>環境は、FreeBSD 4.4です。

No.5342

Re:string.hなしでstrcmp関数などが入ったプログラムが動作したのはなぜ?
投稿者---かずま(2003/02/23 17:42:28)


> strcmpやstrstrを使っているにも関わらず、うっかりstring.hを
> インクルードするのを忘れてコンパイルしてしまいました。
> ところが、コンパイルが通ってしまい、なおかつ問題なく動作
> しています

<string.h> 程度ならインクルードしなくても、たいていのコンパイラで
問題なく動作します。int のサイズと、ポインタのサイズが同じであり、
関数の呼び出し方や値の返し方が同じだからです。

次の例を試してみれば分かるでしょう。
-------- a.c --------
int main(void)
{
    puts(func());
    return 0;
}

-------- b.c --------
char *func(void)
{
    return "hoge";
}

---------------------
GCC:   gcc a.c b.c
BC++:  bcc32 a.c b.c
VC++:  cl a.c b.c
LSI C: lcc a.c b.c

<math.h> の場合は、そうはいきません。
double のサイズは int のサイズとは異なりますし、
関数から値を返すときのレジスタが異なったりしますから。

No.5343

Re:string.hなしでstrcmp関数などが入ったプログラムが動作したのはなぜ?
投稿者---hara(2003/02/23 19:38:37)


なるほど。
ということは、私のビルトイン関数だからという理由はズレていました。
暗黙の宣言でも動作するってことですね。
よく分かってないのに変な返答をしてしまって申し訳ないです。

ついでですが、ビルトイン関数のことです。
以下の (1) と (2) のアセンブラコードはほぼ同じになりました
(gcc 2.95.4 Debian/GNU Linux)。
ビルトイン関数を使わないと call sin します。

処理系固有な話になりますが、たとえば Linux の gcc では sin 関数など
最適化オプションを有効にすると math.h (から読まれるヘッダも含む) で
インライン展開されるようになっています。

似たようなコードになるということは、gcc 内インラインアセンブラで記述
されているんでしょうね。
/* (1) math.hをインクルードしない */
int main(void)
{
extern int printf(const char*, ...);
extern double sin(double);
printf("%f\n", sin(5));
return 0;
}
/* (2) math.hをインクルードする */
#include <math.h>
int main(void)
{
extern int printf(const char*, ...);
printf("%f\n", sin(5));
return 0;
}

% gcc -O -ffast-math -S hoge.c
(-O と -ffast-math は最適化オプション。-S でアセンブリソースを出力)
/* (1) */
main:
pushl %ebp
movl %esp,%ebp
subl $8,%esp
addl $-4,%esp
fldl .LC0
fsin
subl $8,%esp
fstpl (%esp)
pushl $.LC1
call printf
xorl %eax,%eax
leave
ret

/* (2) */
main:
pushl %ebp
movl %esp,%ebp
subl $8,%esp
addl $-4,%esp
fldl .LC33
#APP
fsin
#NO_APP
subl $8,%esp
fstpl (%esp)
pushl $.LC34
call printf
xorl %eax,%eax
leave
ret
※APP はアセンブラプリプロセサで、インラインアセンブラを使うと
※挿入されます (Borland C++ Builder の asm{} みたいなものです)。