第9回 C99規格についての説明と検証

岸 哲夫

 「ISO/IEC 9899 : 1999 - Programming Language C」(略称:C99)規格は1999年12月にISOによって規格化された新機能である.現在はデフォルトで,C99規格で決定した新機能の一部を使用することができる.また,新機能の一部はGNU Cの拡張機能と同一である場合もある.今回はGNU CのC99への対応について,解説とテストを行う. (編集部)

space

 前回までで,GCCにおける拡張機能についての説明を終わりました.

 今回は,「ISO/IEC 9899 : 1999 - Programming Language C」(略称:C99)規格について説明と検証をします.

 連載の第3回(2002年10月号)で少し触れましたが,“-flang -isoc9x”というオプションを指定してコンパイルすることで,このC99規格で決定した新機能の一部を使用することができるはずでしたが,オプション“-flang-isoc9x”は廃止されました.

 現在は,デフォルトでC99規格で決定した新機能の一部を使用することができます.

 なお,新機能の一部がGNU Cの拡張機能と同一である場合もあります.

 また後述しますが,GCCのバージョンによっては,一部の機能でライブラリが対応していなかったり,バグがあるものや実装されていないものもあります.

C99規格の予約語について

 追加された予約語は,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")

のように指定すればわかりやすくなります.

C99規格のマクロ

関数型マクロ呼び出しの際の空引き数

 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");
}

 


NEW記事内インデックス    連載インデックスはこちら   Interfaceのトップ
◆C99規格の予約語について/新しく定義されたマクロとプラグマ/C99規格のマクロ/その他のプリプロセッサ関連
定数の指定方法/配列について/bool型について/long long int型/整数除算に関する規定/複素数型
暗黙の関数宣言と変数宣言/定義済みマクロ__func__と可変長引き数マクロ/列挙型について/inline関数定義/restrictポインタ/変数宣言の位置/配列の初期化について/コンパウンドリテラル(Compound Literal)
isblank/関数やマクロの概略

Copyright 2003 岸 哲夫

Copyright 1997-2017 CQ Publishing Co.,Ltd.