表紙 / 自作ソフト / 日記 / 宝箱 / サイト情報 / 検索
一般 / 新C言語 / 駄文

プログラミング言語 C の新機能


←前頁へ◎表紙へ次頁へ→
 
 

1. 概略
1.1 はじめに
1.2 新しい予約語
1.3 新しいヘッダファイル
2. C プリプロセッサ
2.1 新しいコメント表記方法
2.2 空引数を許された関数型マクロ呼出し
2.3 可変個数引数を持つマクロ定義
2.4 あらかじめ定義されているマクロ名
2.5 プログラミング言語 C 標準プラグマ
2.6 単項演算子 _Pragma
2.7 プリプロセッサ式における整数型
2.8 文字列定数とワイド文字列定数の結合
3. 字句
3.1 ユニバーサルキャラクタ名
3.2 拡張された識別名使用文字
3.3 浮動小数点定数の 16 進数表記
4. 配列
4.1 可変長配列
4.2 構造体中の 0 長配列メンバ
4.3 配列要素中の記憶/型修飾子
5. 整数型
5.1 _Bool 型
5.2 long long int 型
5.3 long long int 型の定数
5.4 整数除算
6. 複素数型
6.1 _Complex 型
6.2 _Imaginary 型
6.3 複素数に関する四則演算
7. 文法一般
7.1 暗黙の関数宣言
7.2 宣言時の暗黙の型
7.3 前定義識別名 __func__
7.4 enum 宣言での余分なカンマ
7.5 inline 関数定義
7.6 restrict ポインタ
7.7 変数宣言と実行コードの位置関係
7.8 指示付きの初期化子 (Designated Initializer)
7.9 複合リテラル (Compound Literal)
7.10 選択文と反復文のブロック化
8. 標準ライブラリ(拡張)
8.1 ctype.h
8.2 float.h
8.3 math.h
8.4 stdarg.h
8.5 stdio.h
8.6 stdlib.h
8.7 wchar.h
8.8 wctype.h
9. 標準ライブラリ(新規)
9.1 complex.h: 複素数
9.2 fenv.h: 浮動小数点環境
9.3 inttypes.h
9.4 stdbool.h
9.5 stdint.h
9.6 tgmath.h: 型総称数学関数
A. 付録
A.1 strftime 書式指定子
A.2 printf の書式

2. C プリプロセッサ

 本章では、プリプロセッサに新たに加わったいくつかの機能と、プリプロセッサに対する変更点について説明します。

2.1 新しいコメント表記方法
 今までのプログラミング言語 C でのコメントの表記法は、/* */ という表記を用いていました。次の例では、青色の部分が示している部分、つまり /* で始まり */ で終わる部分がコメントとして扱われました。

従来型プログラミング言語 C のコメントの例
/*
 * 引数一覧表示プログラム  (c)1999 seclan
 * ver1.00 1999/03/15 最初のバージョン
 */
#include <stdio.h>
int main(int argc, char *argv[])
{
  int i;
  for(i = 0; i < argc; i++){
    printf("%d: %s\n", 
      i,    /* 添え字。今何番目を
            表示しているか */
      argv[i] /* 引数の中身 */
    );
  }
  return 0;   /* 常に正常終了 */
}
/* /* ここはコメント領域 */
/* /* ここの最後の */ は不正 */

一度コメントが始まれば、改行してもコメントは続きます。コメントを終わりにするためには、*/ を記述する必要があります。ここで一つ気をつけなければならないことがあります。それは、コメントのネストはできないということです。例の最後の行を見るとわかるように、最後の 「は不正*/」 がコメントからはみ出してしまい不正になっています。
 従来はこの表記方法しかなかったのですが、この表記方法では一行ですむようなコメントを入力する時にはわざわざ閉じるための */ を入力する必要があり、面倒です。そこで新しいコメント表記法 // の導入です。// を使って書き直した例を次に示します。

最新のプログラミング言語 C のコメントの例
//
// 引数一覧表示プログラム  (c)1999 seclan
// ver1.00 1999/03/15 最初のバージョン
//
#include <stdio.h>
int main(int argc, char *argv[])
{
  int i;
  for(i = 0; i < argc; i++){
    printf("%d: %s\n", 
      i,    // 添え字。今何番目を
           //表示しているか
      argv[i] // 引数の中身
    );
  }
  return 0;   // 常に正常終了
}
// ここはコメント領域 
// /* ここの最後の */ もコメント */

 見ればわかると思いますが、// 型のコメントは、// から始まり、行末までです。従って、例の最後の表記法のようなこともできます。この表記法ならば、/ を二回軽くたたくだけなのでコメントの入力が簡単になります。したがって、プログラマも気楽にわかりやすいコメントを入力できるようになるでしょう (?)。なお、一応言っておきますが従来型のコメントも引き続き利用可能です。
 さて、最後におまけですが、この // という表記法は、プログラミング言語 C++ でのコメントの表記法でもあります。さらに言えば、プログラミング言語 C の祖先となる言語の、プログラミング言語 B でのコメントの表記法でもあります。つまり、コメント表記は先祖帰りをしたというところでしょうか。

2.2 空引数を許された関数型マクロ呼出し
 今までのプリプロセッサでは、関数型マクロを利用するときには、その中に必ず引数を書く必要がありました。例えば、ある値とあるアルファベットを指定するとその二つをくっつけた値に置き換えるマクロを考えましょう (数値の後ろに 'L' の記号を付加して long 型の整数定数にするような場合を考えてください)。しかし、場合によっては、そのアルファベットは不要です(int 型の整数定数には記号は必要ありません)。 今までのプリプロセッサでは、関数型マクロで定義された引数には必ず値を指定する必要がありました。このような要求を満たすためには、従来のプリプロセッサでは、次の例のように記述する必要がありました。

従来型のマクロ定義例
/*
 * cpp: 空マクロサンプル1 (c)1999 seclan
 * ver1.00 1999/04/02 最初のバージョン
 */
#define catval(val,suf) val ## suf
main()
{
  long l = catval(3,L); 
  //3L に展開。

  int  i = catval(3,);
  //記述不可能。未定義の動作。
}

 例の中の赤字の部分は規格の範囲内の記述ではできないものです。もし記述するとその振る舞いは未定義になります。しかし、今度の C 言語の仕様によるプリプロセッサでは、関数型マクロ引数に何も引数をかかなくてもよい形式が許されるようになりました(empty macro arguments)。従って、前述の例は新しいプリプロセッサでは、次のように記述することができます。

新しい C 言語プロプロセッサのマクロ定義例
/*
 * cpp: 空マクロサンプル (c)1999 seclan
 * ver1.00 1999/04/02 最初のバージョン
 */
#define catval(val,suf) val ## suf
main()
{
  long l = catval(3,L);
  //3L に展開。

  int  i = catval(3,);
  //OK。3 に展開が保証される。
}

 このように、今度のプリプロセッサでは応用の範囲が少し広がることになりました。

2.3 可変個数引数を持つマクロ定義
 結構ある要求の一つに、printf のカスタムバージョンを簡単に作りたいというものがありました。例えば、dbg("ok value=%d", val); というようなマクロを呼び出すと、最終的に、printf("debug:ok value=%d", val); のように展開したいというものです。このような方法を実現するためには、今まではいくつかの妥協が必要でした。

従来型の可変個数引数マクロの実現方法
/*
 * cpp: 従来型の可変個数引数マクロの実現方法
 *      (c)1999 seclan
 * ver1.00 1999/04/05 最初のバージョン
 */
#include <stdio.h>
#include <stdarg.h>

#define dbg(arg)  (printf("debug:"), printf arg)

int vadbg(const char *format, ...)
{
  int r;
  va_list va;
  va_start(va, format);
  r  = printf("debug:");
  r += vprintf(format, va);
  va_end(va);
  return r;
}

main()
{
  dbg(("ok value=%d", 1));
  //引数を()で括らなくてはならない

  vadbg("ok value=%d", 1);
  //新たな関数の作成が必要
}

 しかし、今度の仕様のプリプロセッサを使えばこのような可変個数引数を持つマクロが簡単に作成することができるようになるのです。

新しい C 言語の CPP 可変個数引数マクロの例
/*
 * cpp: 新しい C 言語の CPP 可変個数引数マクロの例
 *      (c)1999 seclan
 * ver1.00 1999/04/05 最初のバージョン
 */
#include <stdio.h>

#define dbg(fmt, ...) \
 printf("debug:" fmt, __VA_ARGS__)
#define adbg(...)   \ //(1)これもOK
 printf("debug:" __VA_ARGS__)

main()
{
  int x = 2, y = 4;
  dbg("ok value=%d", 1);
  //通常の printf のように使える!

  dbg("[%u,%u]", x, y);
   //多くてもOK

  adbg("%u", x);    
  //ok

  adbg();       
   //もちろん省略もできる
}

 まず、可変個数引数を持つマクロでは、個数を可変にしたい部分に省略を示す記号「...」をおきます。これは C 言語の省略の記号と同じもので、引数リストの最後にしか置くことができません。この関数型マクロを使うときには、この省略の部分には、まったく引数をかかなくてもいいし、いくつも書いても許されます。また、(1)のように一つも固定部分がないマクロも可能です。そして、マクロの右側ではその部分はマクロ「__VA_ARGS__」でその内容を参照することができます。
 これでプリプロセッサがますます使いやすくなりましたね。

2.4 あらかじめ定義されているマクロ名
 C プリプロセッサでは、あらかじめ定義されているマクロ名があります。これらは事前に定義されているのですぐに参照可能です。従来の C プリプロセッサでも 5 つのマクロ名が定義されていました。その後、9899/AMD1:1995 で 1 つのマクロが追加されました。そして今回新しく 3 個のマクロが定義されました。それらは、次の通りです。

標準定義マクロ
ISO/IEC 規格マクロ名値の例説明
9899:1990 __LINE__12現在の処理中のソースファイル行番号
__FILE__"hello.c"現在処理中のソースファイル名
__DATE__"Apr 01 1999"処理開始時の日付("Mmm dd yyyy")。asctime と同じ形式。
__TIME__"12:34:50"処理開始時の時刻("hh:mm:ss")。asctime と同じ形式。
__STDC__1標準に従っている時定義される
9899/AMD1:1995 __STDC_VERSION__199409LC 言語の仕様のバージョンをあらわす
9899:1999 __STDC_VERSION__199901LC 言語の仕様のバージョンをあらわす
__STDC_ISO_10646__199712LyyyymmLの形式で、wchar_t の表現する文字コードが ISO/IEC 10646(UNICODE)の yyyymm 年の仕様を満たすとき定義
__STDC_IEC_559__1annex F (IEC 60559 浮動小数点) 適合時に定義
__STDC_IEC_559_COMPLEX__1annex G (IEC 60559 互換複素数) に忠実に従っているとき定義

 今回の追加では拡張機能に関する項目が多いことが特徴です。

2.5 プログラミング言語 C 標準プラグマ
 今までの C 言語では、C プリプロセッサにおいて pragma という指令を設けて、それを使用することでベンダ定義の指令を与える方法を定義していました。しかし、これには標準 C 言語自身が提供するプラグマは含まれませんでした。今度の C 言語では、STDC というプラグマを決定し、このプラグマを使用することで標準 C 言語のプラグマを提供することにしました。このプラグマを利用して提供される標準 C 言語のプラグマは以下の通りです。

標準プラグマ
プラグマ説明
#pragma STDC FP_CONTRACT on-off-switch浮動小数点演算で、省略された計算をするかどうか。ここでいう省略とは、浮動小数点演算におけるいくつかの特徴を省くこと。例えば、演算の結果精度落ちなどの例外が発生しても、それを通知しないといったことが挙げられる。省略の結果として、演算の高速化が可能になる可能性がある。デフォルト値は実装依存である。プラグマの有効範囲は通常の変数と同じ扱いになる。したがって、{ } の中でプラグマを使ってもその外に出ればその { } に入る直前の値に戻る。
#pragma STDC FENV_ACCESS on-off-switchfenv.h で定義される浮動小数点環境へのアクセスの有効化、無効化を指定する。浮動小数点環境には、例えば浮動小数点ステータスフラグといったものがある。もし fenv.h で定義される浮動小数点環境を使用しないときには、これを off にすることで高速化をはかることができる。プラグマの有効範囲は通常の変数と同じ扱いとなる。デフォルト値は実装依存である。
#pragma STDC CX_LIMITED_RANGE on-off-switch複素数の掛け算、割り算、絶対値の計算における通常の数学式は無限大の扱いや、適切でないオーバーフローやアンダーフローといった部分に問題がある。そこでこのプラグマをONにすることで通常の数学式でうまく計算するよう指示する。これは、次の計算式の実装を許すものである。
 (x+iy) × (u+iv) = (xu-vy) + i(yu+xv)
 (x+iy) ÷ (u+iv) = [(xu+yv) + i(yu-xv)] ÷ (u2+v2)
 |x+iy| = √(x2 + y2)
プラグマの有効範囲は通常の変数と同じ扱いとなる。デフォルト値は off である。
*注意:
 (1)on-off-switchは ON, OFF, DEFAULT のいずれか。
 (2)#pragma STDC は標準C言語のために予約。ユーザ定義不可。

 新たに定義されたものは、浮動小数点や複素数関係なのでそれらを使わない人はめったに使うことはないでしょう。

2.6 単項演算子 _Pragma
 プラグマはベンダが勝手に定義していくもので、もちろん標準化はされていません。しかし、ベンダ間で同じような機能を持つプラグマが異なった表記法によって定義されることがあります。例えば、そのマシンで多少制限はあるがより高速に呼び出す方法があるとしましょう。このプラグマは直後の関数一つを修飾するものとします。このような場合、移植性のあるソースプログラムにするには、プラグマを次のように使用するしかありませんでした。

従来の #pragma の使用例
/*
 * cpp: 従来の #pragma の使用例 (c)1999 seclan
 * ver1.00 1999/04/25 最初のバージョン
 */
//ここから: 関数毎に記述する必要がある
#if defined(ARCHITECTURE_A)
 #pragma call_func_fast
#elif defined(ARCHITECTURE_B)
 #pragma fastcall
#elif defined(ARCHITECTURE_C)
 #pragma __fastcall
#endif
//ここまで
int func(int val)
{
 ...
}
//ここから: また記述する必要がある
#if defined(ARCHITECTURE_A)
 #pragma call_func_fast
#elif defined(ARCHITECTURE_B)
 #pragma fastcall
#elif defined(ARCHITECTURE_C)
 #pragma __fastcall
#endif
//ここまで:
int foo_bar(int val)
{
 ...
}

 pragma を使用するたびにこのような表記法を使用する必要があります。しかし、この表記ではソースプログラムが非常に見づらくなります。では、より簡単にするために、#if ... #endif の間を別のファイルにして、それを #include するという方法も考えられます。しかしそれぞれのプラグマ用のファイルを作成するのは管理と手間の上で面倒で、しかも美しくありません。今度のプリプロセッサから使用できるプリプロセッサ _Pragma 単項演算子を使用するとこのような問題を解決することができます。

_Pragma 演算子の使用例
/*
 * cpp: _Pragma 演算子の使用例 (c)1999 seclan
 * ver1.00 1999/04/25 最初のバージョン
 */
//ここから: config.h などに定義しておく
#if defined(ARCHITECTURE_A)
 #define pragma_fastcall _Pragma("call_func_fast")
#elif defined(ARCHITECTURE_B)
 #define pragma_fastcall _Pragma("fastcall")
#elif defined(ARCHITECTURE_C)
 #define pragma_fastcall _Pragma("__fastcall")
#else
 #define pragma_fastcall 
#endif
//ここまで

pragma_fastcall int func(int val)  
//簡単に指定できる
{
 ...
}
pragma_fastcall int foo_bar(int val)  
//pragma_fastcall で指定できる
{
 ...
}

 このように、簡潔に記述することができるようになります。なお、_Pragma の引数に書けるのは文字列定数だけです。つまり、_Pragma("プラグマ指令") という表記だけです。

2.7 プリプロセッサ式における整数型
 プリプロセッサでの #if 式 といった、式の中では整数の演算をすることができます。従来のプリプロセッサでは、符号付きの演算では long 型、符号なしでは unsigned long 型で計算がなされました。しかし、そのアーキテクチャで、long 型よりもっと大きな整数型が必要になり、そのためにベンダが独自に新たな整数型を定義したりしているときも、プリプロセッサ中ではそれよりも小さな値しか表現できない long 型で計算するしかありませんでした。
 新しいプリプロセッサでは、符号付きの演算では intmax_t 型で、符号なしでは uintmax_t 型で計算することになりました。intmax_t, uintmax_t は、今度の C 言語で新たに導入された stdint.h の中で定義される型で、この処理系の中で表現されうる最大の数を表現できる符号付き/符号なし整数の型です。

2.8 文字列定数とワイド文字列定数の結合
 C 言語では、並んだ二つの文字列定数は一つの文字列定数に併合する決まりになっています。例えば、文字列定数 "hoehoe " と文字列定数 "room" が並んでいれば、その二つを結合した文字列 "hoehoe room" に、ワイド文字列定数 L"hoehoe " とワイド文字列定数 L"room" が並んでいれば、結合されたワイド文字列定数 L"hoehoe room" に変換されます。しかし、文字列定数とワイド文字列定数に関する結合に関しては未定義の動作となっていました。
 今回の C 言語では、文字列定数とワイド文字列定数は結果として、単一のワイド文字列定数になることになりました。これは、ワイド文字列を使用した関数で、新たに余計なマクロを定義しなくてもすむようにするためです。例えば、inttypes.h で定義されているマクロ PRIxFAST32 などを使うことを考えます。もし今回の決定が無ければ、ワイド版のマクロを別に定義する必要にせまられますが、今回の決定により、wprintf ( L"val=%"PRIxFAST32"\n", intfast32val ) のように何ら不自然ではなく記述することができます。
*構文として定義されていないので、プリプロセッサの機能として分類してあります

←前頁へ◎表紙へ次頁へ→
 
 
表紙 - 著作権 - 注意事項 - リンクについて - 404 エラーについて
(c)1999-2014 seclan. All rights reserved.