C++11 に採用された C99 プリプロセッサー機能 (C++11)

注: IBM は、C++11 (承認前の呼称は C++0x) の、選定された機能をサポートしています。IBM は、この標準の機能の開発および実装を継続します。この言語レベルの実装は、IBM による標準の解釈に基づいています。 新しい C++11 標準ライブラリーのサポートを含め、すべての C++11 機能を IBM が実装し終えるまで、リリースごとに実装が変更される可能性があります。IBM では、IBM による新規 C++11 機能の実装に関し、ソース、バイナリー、リスト作成などのコンパイラー・インターフェースにおいて、以前のリリースとの互換性を維持するための試みは、特に行いません。

C++11 標準では、C および C++ コンパイラーに対して共通プリプロセッサー・インターフェースを提供するために、複数の C99 プリプロセッサー機能が採用されています。 これにより、C ソース・ファイルを C++ コンパイラーに簡単に移植でき、旧式の C プリプロセッサーと C++ プリプロセッサーの間に存在するいくつかのわずかな意味の違いを除去できるため、プリプロセッサーの互換性の問題を解決し、プリプロセッサーが異なる動作を行うことを回避できます。

拡張整数型を使用したプリプロセッサー演算

C89、C++98、および C++03 プリプロセッサーでは、int 型または unsigned int 型を持つ整数リテラルは、long または unsigned long に拡張されます。ただし、C99 および C++11 プリプロセッサーでは、 すべての signed 整数型および unsigned 整数型 (文字型を含む) は、XL C/C++ の通常の環境の下では long long または unsigned long long に拡張されます。

この機能を使用可能にして、-qnolonglong および -qlanglvl=noc99longlong の両方が -q32 モードまたは -q64 モードのいずれかで設定されている場合、プリプロセッサーはプリプロセッサー制御式のすべての整数リテラルおよび文字リテラルに対して、依然として long long または unsigned long long の表記を使用します。

以下の例は、wchar_t の基礎となる型が unsigned short である -q32 モードの AIX® プラットフォームで有効です。
#if L'¥x0' - L'¥x1' < 0 
#error non-C++11 preprocessor arithmetic. 
#else
#error C++11 preprocessor arithmetic! L'¥x0' and L'¥x1' are widened to¥
       unsigned long long 
#endif 
以下の例は、long long サポートが -q32 モードで使用可能になっているケースを示します。この機能を使用すると、非 C++11 プリプロセッサーと C++11 プリプロセッサーの間で異なる組み込み分岐が選択されます。
#if ~0ull == 0u + ~0u 
#error C++11 preprocessor arithmetic! 0u has the same representation as 0ull,¥
       hence ~0ull == 0u + ~0u 
#else 
#error non-C++11 preprocessor arithmetic. 0ul does not have the same ¥
       representation as 0ull, hence ~0ull != 0u + ~0u 
#endif

この機能を無効にして -qwarn0x を設定すると、C++11 プリプロセッサーは、#if ディレクティブおよび #elif ディレクティブの制御式を評価し、評価結果を非 C++11 プリプロセッサーの結果と比較します。結果が異なる場合、コンパイラーはプリプロセッサーの制御式の評価が、C++11 と非 C++11 の言語レベル間で異なることを警告します。

混合ストリング・リテラルの連結

通常のストリングをワイド・ストリング・リテラルと連結できます。以下に例を示します。
#include <wchar.h>
#include <stdio.h>

int main()
{
wprintf(L"Guess what? %ls¥n", "I can now concate" L"nate regular strings¥
        and wide strings!");
printf("Guess what? %ls¥n", L"I can now concate" "nate strings¥
        this way too!");
}
この例を実行すると、以下を出力します。
Guess what? I can now concatenate regular strings and wide strings!
Guess what? I can now concatenate strings this way too!

ヘッダー・ファイルおよびインクルード名の診断

この機能が使用可能であるときに、#include ディレクティブ内のヘッダー・ファイル名の先頭文字が数字である場合、コンパイラーは警告メッセージを出します。次の例を検討してみます。
//inc.C

#include "0x/mylib.h"

int main()
{
return 0;
}
この機能を使用可能にして、この例をコンパイルまたはプリプロセッシングすると、コンパイラーは以下の警告メッセージを出します。
"inc.C", line 1.10: 1540-0893 (W) The header file name "0x/mylib.h" 
in #include directive shall not start with a digit.

#line ディレクティブの制限の引き上げ

#line <integer> プリプロセッサー・ディレクティブの上限が、C99 プリプロセッサーに適合する C++11 プリプロセッサーでは、32,767 から 2,147,483,647 に増えています。
#line 1000000   //Valid in C++11, but invalid in C++98
int main() 
{
    return 0;
} 

オブジェクト類似マクロ定義の診断

マクロ定義内のオブジェクト類似マクロ名とその置換リストとの間に空白文字が存在しない場合、C++11 コンパイラーは警告メッセージを出します。次の例を検討してみます。
//w.C

//With -qnodollar, '$' is not part of the macro name,
//thus it begins the replacement list
#define A$B c 
#define STR2( x ) # x 
#define STR( x ) STR2( x )  
char x[] = STR( A$B ); 
この機能を使用可能にし、-qnodollar を指定して、この例をコンパイルまたはプリプロセッシングすると、コンパイラーは以下の警告メッセージを出します。
"w.C", line 1.10: 1540-0891 (W) Missing white space between 
the identifier "A" and the replacement list.

_Pragma 演算子

_Pragma 演算子は、#pragma ディレクティブを指定する代替方式です。 例えば、以下の 2 つのステートメントは等価です。
#pragma comment(copyright, "IBM 2010")
_Pragma("comment(copyright, ¥"IBM 2010¥")")
以下のコードをコンパイルすると、ストリング IBM 2010 が C++ オブジェクト・ファイルに挿入されます。
_Pragma("comment(copyright, ¥"IBM 2010¥")")
int main() 
{
   return 0;
}

可変数引数マクロおよび空のマクロ引数

C99 および C++11 では可変数引数マクロおよび空のマクロ引数がサポートされています。この機能により、変数引数 ID を __VA_ARGS__ からユーザー定義の ID に名前変更する機構が使用可能になります。次の例を検討してみます。
#define debug(...) fprintf(stderr, __VA_ARGS__) 
#define showlist(...) puts(#__VA_ARGS__)
#define report(test, ...) ((test)?puts(#test): printf(__VA_ARGS__))
debug("Flag"); 
debug("X = %d¥n", x);
showlist(The first, second, and third items.);
report(x>y, "x is %d but y is %d", x, y); 
この例は、プリプロセッシング後に以下のコードに展開されます。
fprintf(stderr, "Flag");
fprintf(stderr, "X = %d¥n", x);
puts("The first, second, and third items.");
((x>y)?puts("x>y"): printf("x is %d but y is %d", x, y));

事前定義マクロ

__STDC_HOSTED__ マクロは、以下のマクロが定義されているかどうかにかかわらず、1 に事前定義されます。
  • __STDC__
  • __STDC_VERSION__
  • __STDC_ISO_10646_