前回までで,GCCにおける拡張機能についての説明を終わりました.
今回は,「ISO/IEC 9899 : 1999 - Programming Language C」(略称:C99)規格について説明と検証をします.
連載の第3回(2002年10月号)で少し触れましたが,“-flang -isoc9x”というオプションを指定してコンパイルすることで,このC99規格で決定した新機能の一部を使用することができるはずでしたが,オプション“-flang-isoc9x”は廃止されました.
現在は,デフォルトでC99規格で決定した新機能の一部を使用することができます.
なお,新機能の一部がGNU Cの拡張機能と同一である場合もあります.
また後述しますが,GCCのバージョンによっては,一部の機能でライブラリが対応していなかったり,バグがあるものや実装されていないものもあります.
追加された予約語は,inline,restrict,_Bool,_Complex,_Imaginaryです.
● inline
従来はC++の予約語でした.第六回で説明したように,C++では使用できてもCでは使用できません.今回は予約語になりましたが,理由があってGNU Cでは機能していません.
-ansiオプションでコンパイルすると,inlineという単語を変数として使用できますが,-ansiオプションがないとC99規格をサポートするので,エラーになります.
ただし,inline関数を指定しても,実質は何もしません.以下は,リスト1のコンパイル結果です.
〔リスト1〕単語inlineを変数としてテスト(test106.c)
|
#include <stdio.h>
/*inlineは予約語?*/
int main(void)
{
int inline;
return;
}
|
|
$ gcc -S -ansi test106.c
$
$ gcc -S test106.c
test106.c: In function `main':
test106.c:5: warning: useless keyword or
type name in empty declaration
test106.c:5: warning: empty declaration
$
● restrict
ポインタの修飾に使用します.そのポインタが別名定義されていない場合に,そのことを明確にコンパイラに知らせるために使用します.
● _Bool
値0か1を保存できるブール変数の型です.
● _Complex
複素数を扱うために使用します.
● _Imaginary
複素数の虚数部だけを扱うために使用します.
● マクロ
__STDC_VERSION__,__STDC_ISO_10646__,__STDC_IEC_559__,__STDC_IEC_559_COMPLEX__の四つの定義済みマクロが使用できます.
詳しくは,GNU Cのプリプロセッサの項で詳細に説明します.
● プラグマ
以下のプラグマ(pragma)が追加されました.
・#pragma STDC FP_CONTRACT on-off-switch
浮動小数点演算の計算方法を指定します.
・#pragma STDC FENV_ACCESS on-off-switch
浮動小数点演算を使用するかどうかを指定します.
・#pragma STDC CX_LIMITED_RANGE on-off-switch
複素数計算をするときに指定します.
詳しくは,GNU Cのプリプロセッサの項で詳細に説明します.
● _Pragmaという単項演算子
プラグマは処理系独自のものなので,標準化を行うことはできません.しかし,可搬性を高めるため,
" #define pragma_FP_CONTRACT _Pragma ("STDC FP_CONTRACT on-off-switch")"
と指定できるようになりました.
この#define文を#if文で制御すれば,環境ごとに対応させることによる#if文の指定も最小限で済みます.また,
#if defined(FP_ENABLE)
#define pragma_FP_CONTRACT _Pragma ("STDC FP_CONTRACT on-off-switch")
のように指定すればわかりやすくなります.
● 関数型マクロ呼び出しの際の空引き数
ANSI Cでは,マクロ呼び出しの際に引き数が必要ないからといって,空の引き数を使用することはできませんでした.しかしC99規格では,そのような呼び出しを許します.
ただ,GNU Cでは-ansiをつけても,-traditionalをつけてコンパイルしてもエラーにはなりませんでした.
リスト2のコンパイルと実行結果を以下に示します.
〔リスト2〕関数型マクロ呼び出しの際の空引き数(test107.c)
|
#define message(errcd,msg) "エラーコード" errcd "です 詳細は" msg
main()
{
printf("%s\n",message("100","err01"));
printf("%s\n",message("200",));
}
|
|
$ gcc -ansi test107.c -o test107
$ ./test107
エラーコード100です 詳細はerr01
エラーコード200です 詳細は
$ gcc -traditional test107.c -o test107
$ ./test107
エラーコード100です 詳細はerr01
エラーコード200です 詳細は
$ gcc test107.c -o test107
$ ./test107
エラーコード100です 詳細はerr01
エラーコード200です 詳細は
$
● 可変個数の引き数をもつマクロ
連載第7回(2003年3月号)で,拡張機能として“可変個数の引き数をもつマクロ”の説明をしましたが,同じことをC99規格でも実現しています.ただし,-ansiオプションをつけるとエラーになります.
リスト3のコンパイルと実行結果を次に示します.
〔リスト3〕可変個数の引き数を持つマクロ(test108.c)
|
/*
*可変個数の引数を持つマクロの例
*/
#include <stdio.h>
#define M_debug(format, ...) printf("debug:" format, __VA_ARGS__)
main()
{
int x01 = 100;
int x02 = 200;
M_debug("x01=%d\n",x01);
M_debug("(%d,%d)\n",x01,x02);
M_debug("(%d,%d,%d行目)\n",x01,x02,__LINE__ );
}
|
|
$ gcc -ansi -pedantic test108.c -o test108
test108.c:5: badly punctuated parameter list in `#define'
$
$ gcc test108.c -o test108
$ ./test108
debug:x01=100
debug:(100,200)
debug:(100,200,13行目)
$
● プリプロセッサ式中の整数型について
プリプロセッサ内部で演算をする際,従来はlongとunsigned longでしか扱えませんでした.
C99規格では,新しく導入されたヘッダ“stdint.h”にあるように,intmax_t型,uintmax_t型が使用できるようになりました.インテルアーキテクチャのGCC 2.95では,以下のように定義されています.
$ cat /usr/include/stdint.h | grep intmax_t
typedef long int intmax_t;
typedef unsigned long int uintmax_t;
typedef long long int intmax_t;
typedef unsigned long long int uintmax_t;
$
● 文字列定数とワイド文字列定数を混在して結合する
文字どおり,通常の文字列定数とワイド文字列を混在して結合することができます.ただし,-traditionalを指定するとエラーになります.
リスト4のコンパイル結果と実行結果を次に示します.
$ gcc test109.c -o test109
$ ./test109
test=aaa
$ gcc -ansi -pedantic test109.c -o test109
$ ./test109
test=aaa
$ gcc -traditional test109.c -o test109
In file included from
/usr/include/features.h:283,
from
/usr/include/inttypes.h:26,
from test109.c:4:
/usr/include/sys/cdefs.h:31: #error
"You need a ISO C conforming compiler to use the glibc headers"
$
〔リスト4〕文字列定数とワイド文字列定数を混在して結合する(test109.c)
|
/*
*文字列定数とワイド文字列定数を混在して結合する
*/
#include <inttypes.h>
main()
{
wprintf(L"test=" "aaa" "\n","\n");
}
|
|
|