-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とした場合でも同じはずです。
この問題を解消するには、-std=c99ではなく、-std=gnu99とします。

http://oshiete1.goo.ne.jp/qa3628763.html

# 抑止されるという表現は見つかりませんでしたが,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~