-std=c99と-std=gnu99は同じ?
四捨五入を計算するround()関数を使う機会があって,
次のようなコードをコンパイルしたところ,
#include <stdio.h> #include <math.h> int main() { int i; double r = 0; for (i=0; i<11; i++, r+=0.1) { printf("\t%.1f\t%f\t%f\n", r, rint(r), round(r)); } return 0; }
$ gcc -Wall -lm round.c round.c: In function 'main': round.c:30: warning: implicit declaration of function 'round' round.c:30: warning: incompatible implicit declaration of built-in function 'round'
というエラーが出ました.
# 一応warningだけでしたので,バイナリは生成されます.実行結果は期待通りのものでした.
round()はC99から登場した関数のようで*1,
これをコンパイルするには-std=c99というコマンドラインオプションをgccに与えなければならないようです.
$ gcc -Wall -std=c99 -lm round.c
これはエラー無しでコンパイルすることができ,実行結果も期待通りのものでした.
今回疑問に思ったのはこのようなコメントを見つけたからです.
-std=c99を指定すると、GNU拡張が抑止されてしまいます。これはC99の問題ではなく、-std=c89とした場合でも同じはずです。
http://oshiete1.goo.ne.jp/qa3628763.html
この問題を解消するには、-std=c99ではなく、-std=gnu99とします。
# 抑止されるという表現は見つかりませんでしたが,gccのマニュアルでは文脈からそのようには読めます.(cf.参考の節:gnu99とc99の違い)
ということは,GNU拡張をわざと使ってみると,
今度はそちらでエラーが表示される(もしくは実行できなくなる)ということでしょうか.
これを確認するために,先のものに追加で次のようなコードを書いてみました.
#include <stdlib.h> #include <stdio.h> #include <math.h> #define dbgmsg(fmt, ...) \ fprintf(stderr, "%s():: " fmt "\n", __func__, ## __VA_ARGS__) void adios() __attribute__ ((noreturn)); void adios(char *s) { puts(s); exit(1); } int main() { int i; double r = 0; double nestedfunc(double z) { return z; } for (i=0; i<11; i++, r+=0.1) { printf("\t%.1f\t%f\t%f\n", r, rint(r), round(r)); dbgmsg("%.1f\t%f\t%f", r, rint(r), round(r)); } printf("%f\n", nestedfunc(r)); adios("bye ^-^/~"); return 0; }
GNU拡張としてはhttp://gcc.gnu.org/onlinedocs/gcc-4.3.2/gcc/index.html#toc_C-Extensionsにおける,
- 5.4 Nested Functions
- 5.17 Macros with a Variable Number of Arguments.
- 5.27 Declaring Attributes of Functions
を使っています.
5.17を除いて*2,これらはC99では使えないはずです.
GNU拡張が抑止されるのであれば,少なくとも実行はできないような気がします.
とりあえず,コンパイル.
$ gcc -Wall -lm round.c round.c: In function 'main': round.c:30: warning: implicit declaration of function 'round' round.c:30: warning: incompatible implicit declaration of built-in function 'round' $ gcc -Wall -std=c99 -lm round.c $ gcc -Wall -std=gnu99 -lm round.c
プリプロセッサオプションのstdを付けてないものは,最初のものと同じエラーが出ます.
これは当然でしょう.
gnu99はGNU拡張とC99を兼ね備えているので,これはよいとして,c99はエラーを出しませんでした.
そして実行結果は,3つとも実行可能で,すべて期待通りの表示でした.
これは...謎です.
なぜでしょうね.
参考
-std=standard -ansi Specify the standard to which the code should conform. Currently CPP knows about C and C++ standards; others may be added in the future. standard may be one of: ~snip~ c99 iso9899:199x c9x The revised ISO C standard, published in December 1999. Before publication, this was known as C9X. gnu89 The 1990 C standard plus GNU extensions. This is the default. gnu99 gnu9x The 1999 C standard plus GNU extensions. ~snip~