Cプリプロセッサは,マクロ置換,条件付きコンパイル,および指定したファイルの取込みを実行する機能を提供します。
前処理命令はプリプロセッサとの連絡に使用する文であり,
その先頭には
#
を付けます。#
の前に空白が存在する場合もあります。
この章の各節では,Compaq Cコンパイラで使用可能な前処理命令および演算子について説明します。
#define
および
#undef
命令と #
および ##
演算子(第8.1節)
#if
,#ifdef
,#ifndef
,
#else
,#elif
,
および #endif
命令と defined
演算子(
第8.2節)
#include
命令(第8.3
節)
#line
命令(第8.4節)
#pragma
命令(第8.5節)
#error
命令(第8.6
節)
#
) (第8.7
節)
前処理命令は通常のスコープの規則とは独立しており,コンパイル単位の終わり, またはその効力が取り消されるまで有効です。
条件付きコンパイルについての詳細は,第8.2 節を参照してください。前処理命令の処理系に依存する定義についての詳細は, プラットフォームに固有のCompaq Cのマニュアルを参照してください。
ANSI規格では,前処理命令に続けるテキストとしてコメントだけを許可しています。 厳密なANSIモード以外のすべてのモードでこの構文規則に違反した場合, Compaq Cコンパイラは警告を出します。厳密なANSIモードで違反した場合には, エラー・メッセージを出します。
#define
命令はマクロ識別子と置換並びを指定し,改行文字で終了します。
置換並び,つまり一連の前処理トークンはプログラム・
テキスト内でマクロ識別子が出現するたびに置き換えられます。ただし,
このマクロ識別子が文字定数,コメント,またはリテラル文字列の内部で出現した場合には置き換えられません。
#undef
命令は,
マクロ定義を取り消す場合に使用されます。
マクロ定義はブロック構造からは独立しており,このマクロを定義している
#define
命令から,それに対応する
#undef
命令またはコンパイル単位の終わりが現れるまで有効です。
#define
命令の構文は次のとおりです。
#define 識別子 置換並び 改行
#define 識別子 (識別子並び(opt)) 置換並び 改行
#define 識別子 ( ... ) 置換並び 改行
#define 識別子 ( 識別子並び, ... ) 置換並び 改行
置換並びが空の場合,その識別子がそれ以降に出現すると ソース・ファイルから削除されます。
#define
命令の1番目の形式を
オブジェクト形式マクロと呼びます。
残りの3つの形式を,関数形式マクロと呼びます。
#undef
命令の構文は次のとおりです。
#undef 識別子 改行
この命令は,#define
によって定義された以前の識別子の定義を取り消します。
以前に定義されたマクロの再定義は,新しい定義が古い定義と厳密に同じではない限り無効になります。
マクロ定義内の置換並びには,関数形式のマクロ参照の実引数と同様に他のマクロ参照を含めることができます。 Compaq Cでは,これらの参照のネストされた深さを制限していません。
所定のマクロ定義により,置換並びに入っているそのマクロ名自体を現在指定している置換並びに置き換えることができます。 ただし,定義しているマクロ名がそのマクロ名自体の置換並び, またはネストされた置換並びに入っている場合にはそのマクロ名は置き換えられません。 この置き換えられなかったマクロ名は後で別の置換が行われる文脈内で検査されても, その置換には使用できなくなります。
次の例は,ネストされた #define
命令を示しています。
/* Show multiple substitutions and listing format. */ #define AUTHOR james + LAST main() { int writer,james,michener,joyce; #define LAST michener writer = AUTHOR; #undef LAST #define LAST joyce writer = AUTHOR; }
この例を,中間マクロ展開を表示させるための適切なオプションでコンパイルすると, 次の並びが生成されます。
1 /* Show multiple substitutions and listing format. */ 2 3 #define AUTHOR james + LAST 4 5 main() 6 { 7 int writer, james, michener, joyce; 8 9 #define LAST michener 10 writer = AUTHOR; 10.1 james + LAST 10.2 michener 11 #undef LAST 12 #define LAST joyce 13 writer = AUTHOR; 13.1 james + LAST 13.2 joyce 14 }
1回目のパスでは,コンパイラは AUTHOR
識別子を
james + LAST
置換並びに置き換えます。2
回目のパスでは,コンパイラは
LAST
識別子を現在定義されている置換並び値に置き換えます。9
行目で LAST
の置換並び値は
michener
識別子になるので,10行目で
michener
に置き換えられます。12
行目で LAST
の置換並び値は
joyce
識別子に再定義されるので,13行目で
joyce
に置き換えられます。
#define
命令を必要に応じて次の行に継続させることができます。
このためには,次に継続行が来る行をバックスラッシュ(
\ )で終了し,その直後に改行文字を入力します。バックスラッシュと改行文字は定義の一部にはなりません。
次の行の先頭文字は,
論理的にはバックスラッシュの直前の文字に隣接します。継続シーケンスとしてのバックスラッシュおよび改行文字は,
どこでも有効です。ただし,
定義行にあるコメントはバックスラッシュまたは改行文字を指定せずに継続させることができます。
他のC処理系との間でプログラムを移植する場合は処理系によって定義するマクロが異なるため, プログラム内で使用するマクロを選択する際には注意が必要です。
次の形式の前処理命令はオブジェクト形式マクロを定義します。これによって, マクロ名はそれ以後に出現するたびに置換並びに置き換えられます。
#define 識別子 置換並び 改行
オブジェクト形式マクロは,別の #define
命令によって再定義することができます。
ただし,この場合は2番目の定義がオブジェクト形式マクロであり,2
つの置換並びが同一でなければなりません。
つまり,2つのファイルにある特定のマクロ定義は整合するものでなければなりません。
オブジェクト形式のマクロ定義は,頻繁に使用されるトークンの記述名を定義します。
一般に,命令を使用してファイルの終わり(
EOF
)の指示子を次のように定義します。
#define EOF (-1)
関数形式のマクロ定義は,仮引数並びを含んでいます。このマクロの参照は関数呼出しに類似しています。 関数を呼び出すと,実行時にプログラムから関数へ制御が渡されます。 マクロが参照されると,ソース・コードがコンパイル時にプログラムへ挿入されます。 仮引数は対応する実引数に置き換えられ, テキストはプログラム・ストリームへ挿入されます。
マクロ定義の識別子並びに ... がある場合, 末尾の引数(区切りのカンマ前処理トークンを含む)は,1つの項目(可変長引数)を 形成するようにマージされます。 このマージによって引数が結合された後の引数の数は, マクロ定義内のパラメータの数(... を除く)より1大きくなります。
反復記号表記を引数内で使用している関数形式マクロの置換並び にある__VA_ARGS__識別子は,パラメータのように扱われます。 また,可変長引数により,この識別子を置き換えるための前処理トークンが 形成されます。
置換並びをマクロ定義から省略すると,そのマクロ参照全体がソース・テキストから消えます。
マクロ置換の例として,一部のシステム上の
ctype.h
ヘッダ・ファイル内で使用可能な
_toupper
ライブラリ・マクロを示します。このマクロは次のように定義します。
#define _toupper(c) ((c) >= 'a' && (c) <= 'z' ? (c) & 0X5F : (c))
_toupper
マクロが参照されると,コンパイラはマクロとその仮引数をこの命令の置換並びに置き換え,
置換並びにある仮引数(この例では
c
)が出現するたびにマクロ参照の実引数を置き換えます。
このC言語のソース・コードの置換並びは次のように翻訳されます。
すなわち,
c
仮引数が小文字('a'
から
'z'
まで)の場合は式を大文字(c & 0X5F
)として評価し,それ以外の場合は式を指定どおりの文字として評価します。
この置換並びでは,if-then-else条件演算子(
?:
)を使用しています。条件演算子についての詳細は,
第6.6節を参照してください。ビット演算子についての詳細は,
第6.5.6項を参照してください。
前処理命令とマクロ参照は,C言語からは独立した構文を持っています。 マクロ定義の指定時には次の規則に従ってください。
#define
命令では,空白,タブ,およびコメントを使用できる。
次の例のデルタ記号( Δ )で示した場所のどこにでも使用できる。
Δ #Δ define Δ 名前 ( Δ 仮引数1Δ ,Δ 仮引数2Δ ) Δ\ Δ トークン文字列Δ
空白,タブ,およびコメントは1つの空白に置き換えられる。
define
と名前の間は少なくとも1
つの空白,タブ,またはコメントで区切らなければならない。
マクロ参照の指定時には次の規則に従ってください。
Δ 名前Δ (Δ 実引数1Δ ,Δ 実引数2Δ )
インクリメント演算子( ++ ),デクリメント演算子(
-- ),代入演算子( += など)
,またはその他の副作用を起こす可能性がある実引数を使用するマクロ実引数を指定することは,
正しいプログラミング技法ではありません。
たとえば,次の実引数は _toupper
マクロに渡してはなりません。
_toupper(p++)
p++
実引数がマクロ定義内で置き換えられると,プログラム・
ストリーム内では次のようになります。
((p++) >= 'a' && (p++) <= 'z' ? (p++) & 0X5F : (p++))
p
は増分されるため,このマクロ置換で出現するたびに異なる値を持ちます。
副作用が起こる可能性を認識していても,
マクロ定義内の置換並びは変更されることがあります。さらに,この変更によって副作用が変わっても警告は出されません。
#
前処理演算子は,次に続く実引数を文字列リテラルに変換する場合に使用します。
#
前処理演算子は,関数形式マクロ定義でのみ使用することができます。
次にその例を示します。
#include <stdio.h> #define PR(id) printf("The value of " #id " is %d\n", id) main() { int i = 10; PR(i); }
生成される出力は,次のとおりです。
The value of i is 10
マクロ呼出しは,次のように展開されます。
/*1*/ printf("The value of " #id " is %d\n", id) /*2*/ printf("The value of " "i" " is %d\n", 10) /*3*/ printf("The value of i is %d\n", 10)
#
単項演算子は,オペランドから文字列を生成します。この例では,
隣接する文字列リテラルが連結されるという事実も示しています。
#
のオペランドに二重引用符またはエスケープ・シーケンスが含まれている場合には,
これらも展開されます。次にその例を示します。
#include <stdio.h> #define M(arg) printf(#arg "is %s\n", arg) main() { M("a\nb\tc"); }
マクロ呼出しは,次のように展開されます。
/*1*/ printf(#arg " is %s\n", arg) /*2*/ printf("\"a\\nb\\tc\"" " is %s\n", "a\nb\tc"); /*3*/ printf("\"a\\nb\\tc\" is %s\n", "a\nb\tc");
##
前処理演算子は,2つのトークンを連結して1つの有効なトークンにする場合に使用します。
次にその例を示します。
#define glue(a,b) a ## b main() { int wholenum = 5000; printf("%d", glue(whole,num)); }
プリプロセッサは, printf("%d",
glue(whole,num));
の行を
printf("%d", wholenum);
に変換します。これが実行されると,
プログラムは5000を表示します。2つのトークンを連結したトークンが有効ではない場合には,
エラーが生じます。
Compaq Cでは,##
演算子はその行にある
#
演算子の前に評価されます。
##
および
#
演算子は,左から右へグループ分けされます。
条件付きコンパイルの制御には,6つの命令を使用することができます。 これらの命令は,指定した条件が真の場合にのみコンパイルされるプログラム・ テキスト・ブロックを区切ります。これらの命令はネストすることができます。 ブロック内のプログラム・テキストは任意に指定でき,前処理命令,C 文などで構成することができます。プログラム・テキスト・ブロックの先頭には, 次の3つの命令のいずれかを指定します。
#if
#ifdef
#ifndef
オプションとして,次の2つの命令のいずれかで代替テキスト・ブロックをセットすることができます。
#else
#elif
ブロックまたは代替ブロックの終わりには,#endif
命令を指定します。
#if
,#ifdef
,または
#ifndef
で判定した条件が真(0以外)の場合には,
それに対応する #else
(または
#elif
)命令から #endif
命令までの行(
存在する場合)は無視されます。
条件が偽(0)の場合には,#if
,#ifdef
,
または #ifndef
命令から
#else
,#elif
,
または #endif
命令までの行が無視されます。
#if
命令の形式は次のとおりです。
#if 定数式 改行
この命令は定数式が真(0以外)かどうかを判定します。オペランドはインクリメント演算子(
++ ),デクリメント演算子(
-- ),sizeof
演算子,ポインタ演算子(
* ),アドレス演算子(&),およびキャスト演算子を含んでいない定数整数式でなければなりません。
定数式中の識別子はマクロ名の場合もあり,そうでない場合もあります。
キーワードや列挙定数などは含みません。定数式には,
defined
前処理演算子を含めることもできます(第8.2.7項を参照してください)。
#if
命令中の定数式はテキスト置換の対象となり,
#define
命令で前に定義された識別子への参照を含めることができます。
置換は式が評価される前に行われます。すべてのマクロ置換が行われた後に残った前処理トークンは,
字句解析形式のトークンになります。
式中で使用した識別子が現在定義されていない場合には,コンパイラはこの識別子を定数0 として処理します。
#ifdef
命令の構文は以下のとおりです。
#ifdef 識別子 改行
この命令は識別子が現在定義されているかどうかを検査します。識別子は,
#define
命令またはコマンド行で定義することができます。
定義された識別子はその後定義が取り消されない限り,現在定義済みであるとみなされます。
#ifndef
命令の構文は以下のとおりです。
#ifndef 識別子 改行
この命令は識別子が現在定義されていないかどうかを検査します。
#else
命令の構文は以下のとおりです。
#else 改行
この命令は,対応する
#if
,#ifdef
,または
#ifndef
命令で判定された条件が偽の場合にコンパイルする代替ソース・
テキストを区別します。#else
命令はオプションです。
#elif
命令の構文は以下のとおりです。
#elif 定数式 改行
#elif
命令は,C言語の
else-if
文の複合使用と類似したタスクを実行します。
この命令は,対応する
#if
,#ifdef
,#ifndef
,
または別の #elif
命令中の定数式が偽であり,さらに
#elif
行の定数式が真である場合にコンパイルする代替ソース行を区別します。
#elif
命令はオプションです。
#endif
命令の構文は以下のとおりです。
#endif 改行
この命令は #if
,#ifdef
,#ifndef
,
#else
,
または #elif
命令のスコープを終了します。
必要な #endif
命令の数は,#elif
または #else
命令のいずれが使用されているかによって異なります。
次に2種類の例を示します。
#if true #if true . . . . . . #elif true . . #else . #if false . . #endif . . #endif #endif
マクロが定義済みであることを確認する別の方法は,
defined
単項演算子を使用する方法です。
defined
演算子の形式は次のいずれかです。
defined 名前
defined (名前)
この形式の式は名前が定義済みの場合には1と評価され,定義済みではない場合には0 と評価されます。
defined
演算子は,#if
命令を1回だけ使用して複数のマクロを検査する場合に特に役に立ちます。
この方法を使用すれば,
多くの #ifdef
または
#ifndef
命令を使用せずに,簡潔な1行だけでマクロ定義を検査することができます。
次にマクロ検査の例を示します。
#ifdef macro1 printf( "Hello!\n" ); #endif #ifndef macro2 printf( "Hello!\n" ); #endif #ifdef macro3 printf("Hello!\n"); #endif
これと同様のマクロ検査を行うために,defined
演算子を単一の
#if
命令中に指定する方法があります。次にその例を示します。
#if defined (macro1) || !defined (macro2) || defined (macro3) printf( "Hello!\n" ); #endif
Compaq Cの論理演算子を使用すると,defined
演算子を論理式の中で組み合わせることができます。
ただし,
defined
は #if
または #elif
前処理命令の評価済みの式でのみ使用できます。
#include
命令は,指定したファイルの内容をコンパイラへ引き渡されるテキスト・
ストリームへ挿入します。標準ヘッダおよびグローバル定義は通常,
#include
命令でプログラム・
ストリームに取り込まれます。#include
命令の形式には,
次の2種類があります。
#include "ファイル名" 改行
#include <ファイル名> 改行
ファイル名の形式は,各プラットフォームに依存します。
ファイル名が引用符で囲まれている場合,指定されたファイルの検索は
#include
命令を含むファイルが存在しているディレクトリから始まります。
ファイルがこのディレクトリにない場合,
またはファイル名が山括弧( < > )で囲まれている場合には,
ファイルの検索は各プラットフォームに定義されている検索規則に従います。
ファイル名が引用符で囲まれている形式の
#include
は一般的に,ユーザ作成のファイルを取り込む場合に使用され,
山括弧形式の
#include
は標準ライブラリ・ファイルを取り込む場合に使用されます。
ファイルの取込みのための検索パスの規則についての詳細は,プラットフォームに固有の Compaq Cのマニュアルを参照してください。
マクロ置換は,#include
前処理命令の中で使用できます。
たとえば,次の2つの命令を使用してファイルを取り込むことができます。
#define macro1 "file.ext" #include macro1
#include
命令の中で使用した定義済みマクロは,次の2
つの受け入れ可能な
#include
ファイル指定の一方に評価されなければなりません。
評価できない場合にはエラーが報告されます。
"ファイル名"
<ファイル名>
取り込まれるファイル自体に #include
命令を含めることができます。
Compaq Cコンパイラには,
取込みのネストされた深さに固有の制限はありませんが,指定できる深さは使用するハードウェアおよびオペレーティング・
システムの制約によって異なります。
コンパイラはコンパイルで使用した各ファイルの行番号に関する情報を追跡し, ターミナルに診断メッセージを表示する際,またはバッチ・モードでのコンパイル時にログ・ ファイルに診断メッセージを記録する際に行番号を使用します。
#line
命令を使用すると,ソース・コードに割り当てた行番号を変更することができます。
この命令は次の行に新しい行番号を与え,
それ以降の行にそれに続く行番号を生成します。この命令は,プログラム・
ソース・ファイルに対して新しいファイル指定を指定することもできます。
#line
命令はコンパイル並び中の行番号は変更せずに,
ターミナル画面またはログ・ファイルへ送られる診断メッセージの中で与えた行番号だけを変更します。
この命令は,Cコードへ前処理された元のソース・
ファイルを参照する場合に役に立ちます。
#line
命令の形式には,次の3種類があります。
#line 整数定数 改行
#line 整数定数 "ファイル名" 改行
#line 前処理トークン 改行
最初の2つの形式では,コンパイラは #line
命令に従って,
整数定数が指定した番号を行に与えます。引用符の中のオプションの
ファイル名は,コンパイラが診断メッセージの中で提供するソース・
ファイルの名前を示します。ファイル名を省略した場合には,
現在のソース・ファイルの名前,または前の
#line
命令の中で指定された最後のファイル名が使用されます。
3番目の形式では,#line
命令の中のマクロは展開された後に解釈されます。
これによって,マクロ呼出しは整数定数
,ファイル名,またはその両方に展開することができます。
その結果生成された #line
命令は,他の2
つの形式のいずれかに一致しなければなりません。その後,必要に応じて処理が行われます。
#pragma
命令は,各プラットフォームに依存する機能を実行するための標準の方法です。
この命令の構文は以下のとおりです。
#pragma 前処理トークン(opt) 改行
サポートされるプラグマは,プラットフォームによって異なります。認識されないプラグマにはすべて情報メッセージが出されます。 サポートされるプラグマの一覧については, プラットフォームに固有のCompaq Cのマニュアルを参照してください。
次のプラグマは,マクロ展開が行われます。
builtins inline linkage standard dictionary noinline module nostandard extern_model member_alignment message use_linkage extern_prefix nomember_alignment
次のプラグマでもマクロ展開が行われますが,これらは主にプリプロセッサ専用モード( つまり,OpenVMSシステムでの/PREPROCESS_ONLY 修飾子,または,Tru64 UNIXシステムでの-Eスイッチの使用)で使用するためのものであり, Compaq Cコンパイラでオブジェクト・モジュールを生成する際には, 通常は使用されません。
_KAP
-KAPC製品にのみ関連する。
define_template
-Compaq C++にのみ関連する。
code_psect
linkage_psect
_nm
接尾語を付加してマクロ展開を抑制することができます。
たとえば,#pragma inline
でのマクロ展開を抑制するには,
#pragma inline_nm
のように指定します。
また,上記のリストにないプラグマのマクロ展開をサポートするために,
すべてのプラグマ
(マクロ展開対象としてすでに指定されているものも含む)には,
マクロ展開の対象となるpragma-name_m
バージョンがあります。
たとえば,#pragma assert
はマクロ展開の対象になりませんが,
#pragma assert_m
はマクロ展開の対象になります。
マクロ参照は,pragma
キーワードの後ろの任意の位置に
記述できます。
例を次に示します。
#define opt inline #define f func #pragma opt(f)
両方のマクロが展開されると,この#pragma
命令は
#pragma inline (func)
になります。
最近のバージョンのコンパイラに追加されているプラグマと,将来のバージョンに追加されるプラグマは, マクロ展開を行わないという事実上の業界標準に準拠するように変更されています。ANSI C では,プラグマのマクロ展開について何の要件も規定していません。
次に,コンパイラが,任意のプラグマのマクロ展開を行うかどうかをどのように決定するかについて説明します。
コンパイル・モードが/STANDARD=COMMON (OpenVMSシステム)または-std0 ( Tru64 UNIXシステム)以外の場合は,ステップ1を行います。
ステップ1:
pragma
に続くトークンがチェックされて,
最近定義されたマクロであるかどうかが判断される。それがマクロであって,
識別子がマクロ展開を行わないプラグマの名前と一致しない場合には,
そのマクロ(関数形式の場合はその仮引数も)だけが展開される。
そのマクロ展開によって作成されたトークンは,ステップ2
で同じ行にある残りのトークンと一緒にそのまま処理される。
すべてのコンパイル・モードで,ステップ2を行います。
ステップ2
pragma
に続く最初のトークンがチェックされて,
マクロ展開を行うプラグマの名前と一致するかどうか判断される。
一致した場合には,そのトークンと同じ行の残りのトークンに対してマクロ展開が適用される。
既知のプラグマに一致するかどうかのテストでは,先頭に2つのアンダスコア(__)
が付いていてもかまいません。たとえば,#pragma
__nostandard
は#pragma nostandard
と同等です。
次の例は,既知のプラグマに一致する名前で直接コーディングされているプラグマについては, 一般にマクロ展開の動作はすべてのモードで同じであり, 下位互換性があることを示しています。下位互換性がないのは,プラグマの名前に既知のプラグマの名前以外を使用してコーディングし, マクロ展開をしてプラグマ名を生成することを予期している場合だけで, これは共通モードでだけ起こります。 この例外は,Tru64 UNIXプリプロセッサとの互換性を維持するために, 共通モードで設けられています。
#define pointer_size error #define m1 e1 #define e1 pointer_size 32 #define standard message #define x disable(all) #define disable(y) enable(y) #pragma pointer_size 32 /* In common mode, Step 1 skipped. In other modes, Step 1 finds that pointer_size is known not to expand. In any mode, Step 2 finds pointer_size is not a pragma requiring expansion. */ #pragma m1 /* In common mode, Step 1 skipped. In other modes, Step 1 expands m1 to pointer_size 32. In common mode, Step 2 finds m1 is not a pragma requiring expansion. In other modes, Step 2 finds pointer_size is not a pragma requiring expansion. */ #pragma standard x /* In common mode, Step 1 skipped. In other modes, Step 1 expands to message x. In common mode, Step 2 expands to message enable(all). In other modes, Step 2 expands message x to message enable(all). */
#error
前処理命令は,Eレベルの診断メッセージを表示して
コンパイルを続行しますが,オブジェクト・モジュールは生成しません。
この命令の構文は次のとおりです。
#error メッセージ(opt) 改行
#
改行 形式の前処理命令は空命令であり,何の処理も行われません。
これ以降の項ではあらかじめ定義されたマクロについて説明します。これらのマクロは, コードの移植および多くのプログラムに共通する単純なタスクの実行を支援するために提供されています。
__DATE__マクロは,コンパイル開始日を示す文字列リテラルを表します。 形式は次のとおりです。
" Mmm dd yyyy "
月の名前は,asctime
ライブラリ関数によって生成されるものと同じです。dd
が10未満の場合には,最初の d
は空白です。次にその例を示します。
printf("%s",_ _DATE_ _);
このマクロの値は1つの翻訳単位内では一定です。
__FILE__マクロは,現在のソース・ファイルのファイル指定を指定する文字列リテラルを表します。 次にその例を示します。
printf("file %s", _ _FILE_ _);
__LINE__マクロは,そのマクロ参照を含むソース・ファイルの行番号を指定する10 進定数を表します。次にその例を示します。
printf("At line %d in file %s", _ _LINE_ _, _ _FILE_ _);
__TIME__マクロは,コンパイルの開始時刻を示す文字列を表します。時刻の形式は次のとおりです(
asctime
関数と同様です)。
hh : mm : ss
次にその例を示します。
printf("%s", _ _TIME_ _);
このマクロの値は1つの翻訳単位内では一定です。
__STDC__マクロは,規格合致の処理系であることを示す整数定数1を表します。
このマクロの値は1つの翻訳単位内では一定です。
__STDC_HOSTED__マクロは,ホスト処理系の場合には整数定数1と評価され, ホスト処理系でない場合には整数定数0と評価されます。
__STDC_VERSION__マクロは,整数定数199901Lと評価されます。
__STDC_ISO_10646__マクロは,yyyymmL (たとえば,199712L)
の形式の整数定数と評価されます。
このマクロは,wchar_t
型の値が,
ISO/IEC 10646 (指定された年月までのすべての改正(amendment)および
技術的訂正(technical corrigenda)を含む)で定義されている文字のコード化表現
であることを示します。
Compaq Cでは,プログラムを実行しているシステムを識別するために使用するプラットフォーム固有のマクロを定義することができます。 これらのマクロは,プログラムをDECのシステムまたは他社のシステムのいずれで実行するのか, あるいはどのDEC Cプラットフォームで実行するのかに応じて,条件付きで実行するコードを記述する際に役に立ちます。
これらのマクロ定義を使用すれば,移植不可能なコードを条件付きコンパイル・ セクションに囲い込むことによって,Cプログラムにおける移植可能なコードと移植不可能なコードを分離することができます。
さらに,これらのマクロ定義を使用して,複数のオペレーティング・システムで使用されるC プログラムのセクションを条件付きでコンパイルし, システム固有の機能を有効に利用することもできます。条件付きコンパイルの前処理命令の使用についての詳細は, 第8.2 節を参照してください。
システム識別マクロの一覧については,プラットフォームに固有のCompaq C のマニュアルを参照してください。
__func__宣言済み識別子は,関数名の綴りで初期化された,
char
型の静的配列として評価されます。
この識別子は,関数定義本体内のどこからでも認識できます。
たとえば,次のように定義された関数は,"f1"を出力します。
void f1(void) {printf("%s\n", __func__);}