8 前処理命令とあらかじめ定義されたマクロ

Cプリプロセッサは,マクロ置換,条件付きコンパイル,および指定したファイルの取込みを実行する機能を提供します。 前処理命令はプリプロセッサとの連絡に使用する文であり, その先頭には # を付けます。# の前に空白が存在する場合もあります。

この章の各節では,Compaq Cコンパイラで使用可能な前処理命令および演算子について説明します。

前処理命令は通常のスコープの規則とは独立しており,コンパイル単位の終わり, またはその効力が取り消されるまで有効です。

条件付きコンパイルについての詳細は,第8.2 節を参照してください。前処理命令の処理系に依存する定義についての詳細は, プラットフォームに固有のCompaq Cのマニュアルを参照してください。

ANSI規格では,前処理命令に続けるテキストとしてコメントだけを許可しています。 厳密なANSIモード以外のすべてのモードでこの構文規則に違反した場合, Compaq Cコンパイラは警告を出します。厳密なANSIモードで違反した場合には, エラー・メッセージを出します。

8.1 マクロ定義(#defineおよび#undef)

#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処理系との間でプログラムを移植する場合は処理系によって定義するマクロが異なるため, プログラム内で使用するマクロを選択する際には注意が必要です。

8.1.1 オブジェクト形式マクロ

次の形式の前処理命令はオブジェクト形式マクロを定義します。これによって, マクロ名はそれ以後に出現するたびに置換並びに置き換えられます。

     #define 識別子  置換並び  改行

オブジェクト形式マクロは,別の #define命令によって再定義することができます。 ただし,この場合は2番目の定義がオブジェクト形式マクロであり,2 つの置換並びが同一でなければなりません。 つまり,2つのファイルにある特定のマクロ定義は整合するものでなければなりません。

オブジェクト形式のマクロ定義は,頻繁に使用されるトークンの記述名を定義します。 一般に,命令を使用してファイルの終わり( EOF )の指示子を次のように定義します。

     #define  EOF (-1)

8.1.2 関数形式マクロ

関数形式のマクロ定義は,仮引数並びを含んでいます。このマクロの参照は関数呼出しに類似しています。 関数を呼び出すと,実行時にプログラムから関数へ制御が渡されます。 マクロが参照されると,ソース・コードがコンパイル時にプログラムへ挿入されます。 仮引数は対応する実引数に置き換えられ, テキストはプログラム・ストリームへ挿入されます。

マクロ定義の識別子並びに ... がある場合, 末尾の引数(区切りのカンマ前処理トークンを含む)は,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項を参照してください。

8.1.2.1 マクロ定義指定の規則

前処理命令とマクロ参照は,C言語からは独立した構文を持っています。 マクロ定義の指定時には次の規則に従ってください。

8.1.2.2 マクロ参照指定の規則

マクロ参照の指定時には次の規則に従ってください。

8.1.2.3 マクロ実引数における副作用

インクリメント演算子( ++ ),デクリメント演算子( -- ),代入演算子( += など) ,またはその他の副作用を起こす可能性がある実引数を使用するマクロ実引数を指定することは, 正しいプログラミング技法ではありません。 たとえば,次の実引数は _toupperマクロに渡してはなりません。

     _toupper(p++)

p++実引数がマクロ定義内で置き換えられると,プログラム・ ストリーム内では次のようになります。

     ((p++) >= 'a' && (p++) <= 'z' ? (p++) & 0X5F : (p++))

p は増分されるため,このマクロ置換で出現するたびに異なる値を持ちます。 副作用が起こる可能性を認識していても, マクロ定義内の置換並びは変更されることがあります。さらに,この変更によって副作用が変わっても警告は出されません。

8.1.3 文字列リテラルへの変換(#)

#前処理演算子は,次に続く実引数を文字列リテラルに変換する場合に使用します。 #前処理演算子は,関数形式マクロ定義でのみ使用することができます。 次にその例を示します。

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

8.1.4 トークンの連結(##)

##前処理演算子は,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では,##演算子はその行にある #演算子の前に評価されます。 ## および #演算子は,左から右へグループ分けされます。

8.2 条件付きコンパイル(#if ,#ifdef,#ifndef,#else,#elif,#endif,defined)

条件付きコンパイルの制御には,6つの命令を使用することができます。 これらの命令は,指定した条件が真の場合にのみコンパイルされるプログラム・ テキスト・ブロックを区切ります。これらの命令はネストすることができます。 ブロック内のプログラム・テキストは任意に指定でき,前処理命令,C 文などで構成することができます。プログラム・テキスト・ブロックの先頭には, 次の3つの命令のいずれかを指定します。

オプションとして,次の2つの命令のいずれかで代替テキスト・ブロックをセットすることができます。

ブロックまたは代替ブロックの終わりには,#endif 命令を指定します。

#if#ifdef,または #ifndef で判定した条件が真(0以外)の場合には, それに対応する #else (または #elif )命令から #endif命令までの行( 存在する場合)は無視されます。

条件が偽(0)の場合には,#if#ifdef, または #ifndef命令から #else#elif, または #endif命令までの行が無視されます。

8.2.1 #if 命令

#if命令の形式は次のとおりです。

   #if  定数式  改行

この命令は定数式が真(0以外)かどうかを判定します。オペランドはインクリメント演算子( ++ ),デクリメント演算子( -- ),sizeof演算子,ポインタ演算子( * ),アドレス演算子(&),およびキャスト演算子を含んでいない定数整数式でなければなりません。

定数式中の識別子はマクロ名の場合もあり,そうでない場合もあります。 キーワードや列挙定数などは含みません。定数式には, defined前処理演算子を含めることもできます(第8.2.7項を参照してください)。

#if命令中の定数式はテキスト置換の対象となり, #define命令で前に定義された識別子への参照を含めることができます。 置換は式が評価される前に行われます。すべてのマクロ置換が行われた後に残った前処理トークンは, 字句解析形式のトークンになります。

式中で使用した識別子が現在定義されていない場合には,コンパイラはこの識別子を定数0 として処理します。

8.2.2 #ifdef 命令

#ifdef命令の構文は以下のとおりです。

   #ifdef  識別子  改行

この命令は識別子が現在定義されているかどうかを検査します。識別子は, #define 命令またはコマンド行で定義することができます。 定義された識別子はその後定義が取り消されない限り,現在定義済みであるとみなされます。

8.2.3 #ifndef 命令

#ifndef命令の構文は以下のとおりです。

   #ifndef  識別子  改行

この命令は識別子が現在定義されていないかどうかを検査します。

8.2.4 #else 命令

#else命令の構文は以下のとおりです。

   #else  改行

この命令は,対応する #if#ifdef,または #ifndef命令で判定された条件が偽の場合にコンパイルする代替ソース・ テキストを区別します。#else命令はオプションです。

8.2.5 #elif 命令

#elif命令の構文は以下のとおりです。

   #elif  定数式  改行

#elif命令は,C言語の else-if文の複合使用と類似したタスクを実行します。 この命令は,対応する #if#ifdef#ifndef, または別の #elif命令中の定数式が偽であり,さらに #elif行の定数式が真である場合にコンパイルする代替ソース行を区別します。 #elif命令はオプションです。

8.2.6 #endif 命令

#endif命令の構文は以下のとおりです。

   #endif  改行

この命令は #if#ifdef#ifndef#else, または #elif命令のスコープを終了します。

必要な #endif命令の数は,#elif または #else命令のいずれが使用されているかによって異なります。 次に2種類の例を示します。

     #if true                             #if true
     .                                    .
     .                                    .
     .                                    .
     #elif true                           .
     .                                    #else
     .                                    #if false
     .                                    .
     #endif                               .
                                          .
                                          #endif
                                          #endif

8.2.7 defined演算子

マクロが定義済みであることを確認する別の方法は, 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前処理命令の評価済みの式でのみ使用できます。

8.3 ファイルの取込み(#include)

#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コンパイラには, 取込みのネストされた深さに固有の制限はありませんが,指定できる深さは使用するハードウェアおよびオペレーティング・ システムの制約によって異なります。

8.4 明示的な行番号付け(#line)

コンパイラはコンパイルで使用した各ファイルの行番号に関する情報を追跡し, ターミナルに診断メッセージを表示する際,またはバッチ・モードでのコンパイル時にログ・ ファイルに診断メッセージを記録する際に行番号を使用します。

#line命令を使用すると,ソース・コードに割り当てた行番号を変更することができます。 この命令は次の行に新しい行番号を与え, それ以降の行にそれに続く行番号を生成します。この命令は,プログラム・ ソース・ファイルに対して新しいファイル指定を指定することもできます。 #line命令はコンパイル並び中の行番号は変更せずに, ターミナル画面またはログ・ファイルへ送られる診断メッセージの中で与えた行番号だけを変更します。 この命令は,Cコードへ前処理された元のソース・ ファイルを参照する場合に役に立ちます。

#line命令の形式には,次の3種類があります。

   #line  整数定数  改行
   #line  整数定数  "ファイル名"  改行
   #line  前処理トークン  改行

最初の2つの形式では,コンパイラは #line命令に従って, 整数定数が指定した番号を行に与えます。引用符の中のオプションの ファイル名は,コンパイラが診断メッセージの中で提供するソース・ ファイルの名前を示します。ファイル名を省略した場合には, 現在のソース・ファイルの名前,または前の #line命令の中で指定された最後のファイル名が使用されます。

3番目の形式では,#line命令の中のマクロは展開された後に解釈されます。 これによって,マクロ呼出しは整数定数 ファイル名,またはその両方に展開することができます。 その結果生成された #line命令は,他の2 つの形式のいずれかに一致しなければなりません。その後,必要に応じて処理が行われます。

8.5 処理系固有の前処理命令(#pragma)

#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コンパイラでオブジェクト・モジュールを生成する際には, 通常は使用されません。


注意
上記のマクロのいずれにも, _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)になります。


注意
マクロ展開はCompaq Cの初期のバージョンに導入されたプラグマの特徴であり, 下位互換性のために保持されています。

最近のバージョンのコンパイラに追加されているプラグマと,将来のバージョンに追加されるプラグマは, マクロ展開を行わないという事実上の業界標準に準拠するように変更されています。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). */

8.6 エラー命令(#error)

#error前処理命令は,Eレベルの診断メッセージを表示して コンパイルを続行しますが,オブジェクト・モジュールは生成しません。 この命令の構文は次のとおりです。

   #error  メッセージ(opt)  改行

8.7 空命令(#)

#改行 形式の前処理命令は空命令であり,何の処理も行われません。

8.8 あらかじめ定義されたマクロ名

これ以降の項ではあらかじめ定義されたマクロについて説明します。これらのマクロは, コードの移植および多くのプログラムに共通する単純なタスクの実行を支援するために提供されています。

8.8.1 __DATE__マクロ

__DATE__マクロは,コンパイル開始日を示す文字列リテラルを表します。 形式は次のとおりです。

   "    Mmm     dd     yyyy    "

月の名前は,asctimeライブラリ関数によって生成されるものと同じです。dd が10未満の場合には,最初の d は空白です。次にその例を示します。

     printf("%s",_ _DATE_ _);

このマクロの値は1つの翻訳単位内では一定です。

8.8.2 __FILE__マクロ

__FILE__マクロは,現在のソース・ファイルのファイル指定を指定する文字列リテラルを表します。 次にその例を示します。

     printf("file %s", _ _FILE_ _);

8.8.3 __LINE__マクロ

__LINE__マクロは,そのマクロ参照を含むソース・ファイルの行番号を指定する10 進定数を表します。次にその例を示します。

     printf("At line %d in file %s", _ _LINE_ _, _ _FILE_ _);

8.8.4 __TIME__マクロ

__TIME__マクロは,コンパイルの開始時刻を示す文字列を表します。時刻の形式は次のとおりです( asctime関数と同様です)。

   hh    :    mm    :    ss

次にその例を示します。

     printf("%s", _ _TIME_ _);

このマクロの値は1つの翻訳単位内では一定です。

8.8.5 __STDC__マクロ

__STDC__マクロは,規格合致の処理系であることを示す整数定数1を表します。

このマクロの値は1つの翻訳単位内では一定です。

8.8.6 __STDC_HOSTED__マクロ

__STDC_HOSTED__マクロは,ホスト処理系の場合には整数定数1と評価され, ホスト処理系でない場合には整数定数0と評価されます。

8.8.7 __STDC_VERSION__マクロ

__STDC_VERSION__マクロは,整数定数199901Lと評価されます。

8.8.8 __STDC_ISO_10646__マクロ

__STDC_ISO_10646__マクロは,yyyymmL (たとえば,199712L) の形式の整数定数と評価されます。 このマクロは,wchar_t型の値が, ISO/IEC 10646 (指定された年月までのすべての改正(amendment)および 技術的訂正(technical corrigenda)を含む)で定義されている文字のコード化表現 であることを示します。

8.8.9 システム識別マクロ

Compaq Cでは,プログラムを実行しているシステムを識別するために使用するプラットフォーム固有のマクロを定義することができます。 これらのマクロは,プログラムをDECのシステムまたは他社のシステムのいずれで実行するのか, あるいはどのDEC Cプラットフォームで実行するのかに応じて,条件付きで実行するコードを記述する際に役に立ちます。

これらのマクロ定義を使用すれば,移植不可能なコードを条件付きコンパイル・ セクションに囲い込むことによって,Cプログラムにおける移植可能なコードと移植不可能なコードを分離することができます。

さらに,これらのマクロ定義を使用して,複数のオペレーティング・システムで使用されるC プログラムのセクションを条件付きでコンパイルし, システム固有の機能を有効に利用することもできます。条件付きコンパイルの前処理命令の使用についての詳細は, 第8.2 節を参照してください。

システム識別マクロの一覧については,プラットフォームに固有のCompaq C のマニュアルを参照してください。

8.9 __func__宣言済み識別子

__func__宣言済み識別子は,関数名の綴りで初期化された, char型の静的配列として評価されます。 この識別子は,関数定義本体内のどこからでも認識できます。

たとえば,次のように定義された関数は,"f1"を出力します。

void f1(void) {printf("%s\n", __func__);}