コンテンツにスキップ

C言語/前処理指令

出典: フリー教科書『ウィキブックス(Wikibooks)』


ソースプログラムをコンパイルする前に、ソースプログラムに対して行われる前処理をプリプロセス( preprocess )といいます。 このプリプロセスを行なうプログラムのことをプリプロセッサ( preprocessor )と呼びます。 多くのコンパイラがプリプロセッサの機能を兼ね備えていますが、cpp(1) として単体で呼び出すことも出来る場合あります。

プリプロセッシングディレクティブの基本

[編集]

構文

[編集]
preprocessing-file:
    groupopt
group:
    group-part
    group group-part
group-part:
    if-section
    control-line
    text-line
    # non-directive
if-section:
    if-group elif-groupsopt else-groupopt endif-line
if-group:
    # if constant-expression new-line groupopt
    # ifdef identifier new-line groupopt
    # ifndef identifier new-line groupopt
elif-groups:
    elif-group
    elif-groups elif-group
elif-group:
    # elif constant-expression new-line groupopt
    # elifdef identifier new-line groupoptC23
    # elifndef identifier new-line groupoptC23
else-group:
    # else new-line groupopt
endif-line:
    # endif new-line
control-line:
    # include pp-tokens new-line
    # define identifier replacement-list new-line
    # define identifier lparen identifier-listopt) replacement-list new-line
    # define identifier lparen ... ) replacement-list new-line
    # define identifier lparen identifier-list , ... )
    replacement-list new-line
    # undef identifier new-line
    # line pp-tokens new-line
    # error pp-tokensoptnew-line
    # pragma pp-tokensoptnew-line
    # new-line
 text-line:
    pp-tokensoptnew-line
non-directive:
    pp-tokens new-line
lparen:
    a ( character not immediately preceded by white space
replacement-list:
    pp-tokensopt
pp-tokens:
    preprocessing-token
    pp-tokens preprocessing-token
new-line:
    the new-line character
identifier-list:
    identifier
    identifier-list , identifier
pp-parameter:
    pp-parameter-name pp-parameter-clauseopt
pp-parameter-name:
    pp-standard-parameter
    pp-prefixed-parameter
pp-standard-parameter:
    identifier
pp-prefixed-parameter:
    identifier :: identifier
pp-parameter-clause:
    ( pp-balanced-token-sequenceopt )
pp-balanced-token-sequence:
    pp-balanced-token
    pp-balanced-token-sequence pp-balanced-token
pp-balanced-token:
    ( pp-balanced-token-sequenceopt )
    [ pp-balanced-token-sequenceopt ]
    { pp-balanced-token-sequenceopt }
    any pp-token other than a parenthesis, a bracket, or a brace
embed-parameter-sequence:
    pp-parameter
    embed-parameter-sequence pp-parameter

規則と制約

[編集]

プリプロセッシングディレクティブ( preprocessing directive; JIS用語では「前処理指令」 )は、以下の制約を満たすプリプロセッシングトークン( preprocessing tokens; JIS用語では「前処理トークン」)のシーケンスで構成されています[1]

  1. シーケンス内の最初のトークンは、(翻訳フェーズ4の開始時点で)ソースファイル内の最初の文字であり、(改行文字を含まない空白をオプションで含む)空白の後にあります。
  2. プリプロセッサディレクティブは、プリプロセッサトークンのシーケンスで構成されます。このシーケンスの最初のトークンは、#文字で始まります。この#文字は、ソースファイル内の最初の文字として出現するか、または少なくとも1つの改行文字を含む空白の後に続く必要があります。シーケンスの最後のトークンは、そのシーケンス内の最初のトークンの直後に続く最初の改行文字です。
  3. プリプロセッサディレクティブは一般的に「行」と呼ばれますが、これらの行には構文的意味はありません。プリプロセッシング中は、空白はすべて同等ですが、特定の状況でのみ異なります。
  4. テキスト行は、#プリプロセッシングトークンで始まってはいけません。また、非ディレクティブは、指定された構文内に現れるディレクティブ名で始まってはいけません。
  5. 一部のプリプロセッシングディレクティブは、プリプロセッサパラメータを使用して追加情報を取ります。プリプロセッサパラメータ(pp-parameter)は、プリプロセッサプレフィックス付きパラメータ(実装定義のプリプロセッサパラメータに識別子が付され、pp-prefixed-parameterとして識別されます)またはプリプロセッサ標準パラメータ(この文書で指定されたpp-parameters用のpp-standard-parameterとして識別されます)のいずれかでなければなりません。
  6. 識別子pp_paramと__pp_param__形式の識別子として指定されるプリプロセッサ標準パラメータは、スペルを除いて、プリプロセッサパラメータとして使用されるときに同じ動作をします。
  7. 例1 したがって、2つのバイナリリソースインクルージョンディレクティブのプリプロセッサパラメータ
    #embed "boop.h" limit(5) 
    #embed "boop.h" __limit__(5)
    
    は同じように動作し、自由に交換できます。実装は、提供するプリプロセッサパラメータ(プリプロセッサプレフィックス付きパラメータを含む)についても同様の動作をするように奨励されています。
  8. スキップされるグループ内のディレクティブ構文は、ディレクティブ名と次の改行文字の間にプリプロセッシングトークンのシーケンスが出現することが許可されます。

これらの規定により、C言語のプリプロセッサが正しく解釈され、ソースコードの事前処理が適切に実行されることが保証されます。

条件付き取り込み

[編集]

条件付き取り込み( Conditional inclusion )を制御する式は、以下を除き、整数の定数式でなければなりません[2][3]

識別子(キーワードと同一のものを含む)は以下のように解釈されます。

形式
    defined ''identifier''

または

    defined ( ''identifier'' )

識別子がマクロ名として現在定義されている場合 (つまり、定義済みであるか、同じ識別子を持つ #undef 指令を介さずに #define 前処理指令の対象となっている場合)、1 に評価され、そうでない場合は 0 に評価されます。

条件付包含式( conditional inclusion expression )は、以下の形式の単項演算子式を含むことができます。
    __has_c_attribute ( ''pp-tokens'' )

この演算子式は、pp-tokens を属性トークンとして解釈して指定された名前の属性を実装がサポートしている場合は、整数定数の形式に一致する0でないpp-numberで置き換えられ、そうでない場合は0で置き換えられます。pp-tokensは,属性トークンの形式に一致しなければならない。

すべてのマクロ置換が行われた後に(制御式となる前処理トークンのリストに)残る各前処理トークンは、トークンの語彙形式でなければならない(§ 6.4)。
セマンティクス
また、#ifdef、#ifndef、および定義済み条件付き包含演算子は、 __has_c_attribute を定義済みマクロの名前であるかのように扱うものとします。識別子 __has_c_attribute は、本節で言及されていないいかなる文脈にも登場してはなりません。
以下の形式の前処理用ディレクティブ

# if ''identifier'' ''new-line'' ''group''<sub>opt</sub> # elif ''identifier'' ''new-line'' ''group''<sub>opt</sub> という形式の前処理指令は、制御定数式がゼロ以外で評価されるかどうかをチェックします。

評価の前に、制御する定数式となる前処理トークンのリスト内のマクロ呼び出しは、通常のテキストと同様に置き換えられます(定義された単項演算子によって変更されたマクロ名を除く)。この置換処理の結果として定義されたトークンが生成されたり、定義された単項演算子の使用がマクロ置換前の 2 つの指定された形式のうちの 1 つと一致しない場合、その動作は未定義です。マクロの展開とdefinedおよび__has_c_attribute単項演算子の評価によるすべての置き換えが行われた後、残りのすべての識別子(キーワードと語彙的に同一のものを含む)がpp-number 0に置き換えられ[4]、その後、各前処理トークンがトークンに変換されます。結果のトークンは、6.6の規則に従って評価される制御定数式を構成します。このトークンの変換と評価のために,すべての符号付き整数型とすべての符号なし整数型は,それぞれヘッダー<stdint.h>で定義されているintmax_t型とuintmax_t型と同じ表現を持っているかのように振る舞います。これには、文字定数の解釈も含まれており、エスケープシーケンスを実行文字セットのメンバーに変換する必要がある場合もあります。これらの文字定数の数値が、同一の文字定数が式の中(#ifや#elif指令の中を除く)に現れたときに得られる値と一致するかどうかは、実装で定義されます。また、1文字の文字定数が負の値を持つことができるかどうかは、実装で定義される。
以下の形式の前処理用ディレクティブ

# ifdef ''constant-expression'' ''new-line'' ''group''<sub>opt</sub> # ifndef ''constant-expression'' ''new-line'' ''group''<sub>opt</sub> は、識別子がマクロ名として現在定義されているかどうかをチェックする。これらの条件は、それぞれ #if defined identifier および #if !defined identifier と同じです。

各ディレクティブの条件は、順にチェックされます。入れ子になっている条件式のレベルを把握するために、指令は指令を決定する名前のみで処理され、残りの指令の前処理トークンは無視され、グループ内の他の前処理トークンも無視されます。制御条件が真(0以外)と評価された最初のグループだけが処理され、それ以降のグループはスキップされ、その制御指令はスキップされたグループに含まれているかのように処理されます。どの条件も真と評価されず、#else ディレクティブがある場合は、#else で制御されるグループが処理されます。#else ディレクティブがない場合は、#endif までのすべてのグループがスキップされます。
/* Fallback for compilers not yet implementing this feature. */
#ifndef __has_c_attribute
#define __has_c_attribute(x) 0
#endif /*
__has_c_attribute */
#if __has_c_attribute(fallthrough)
/* Standard attribute is available, use it. */
#define FALLTHROUGH [[fallthrough]]
#elif __has_c_attribute(vendor::fallthrough)
/* Vendor attribute is available, use it. */
#define FALLTHROUGH [[vendor::fallthrough]]
#else
/* Fallback implementation. */
#define F

前方参照:マクロの置換(6.10.3)、ソースファイルのインクルード(6.10.2)、最大の整数型

未定義マクロの値

[編集]

マクロ展開と定義済み単項演算子による置換がすべて実行された後、残りのすべての識別子(キーワードと語彙的に同一のものを含む)は pp-number[5] 0 に置換されます[6]。したがって、未定義マクロの値は 0 となります。

ソースファイル取り込み

[編集]

ソースファイル取り込み( Source file inclusion )とは、他のソースファイルを取り込む前処理指令です[7][8]

制約
#include ディレクティブは、インプリメンテーションによって処理可能なヘッダーまたはソースファイルを特定するものです。
セマンティクス
以下の形式の前処理用ディレクティブ
    # include < ''h-char-sequence'' > ''new-line''

この形式は、実装で定義されている一連の場所を検索して、 < と > の間の指定された順序で一意に識別されるヘッダーを探し、 そのディレクティブをヘッダーの内容全体で置き換える。どのように場所を指定するか、どのようにヘッダーを特定するかは、実装で定義されます。

以下の形式の前処理用ディレクティブ
    # include " ''q-char-sequence'' " ''new-line''

は、" デリミタ "の間の指定された順序で特定されるソースファイルの内容全体で、その指示を置き換えます。指定されたソースファイルは、実装で定義された方法で検索されます。この検索がサポートされていない場合や、検索に失敗した場合は、次のように書かれているかのように、指令が再処理されます。

    # include < ''h-char-sequence'' > ''new-line''

は、元のディレクティブと同じ内容のシーケンス(もしあれば > 文字を含む)で置き換えられます[9]

以下の形式の前処理用ディレクティブ
    # include ''pp-tokens'' ''new-line'' 

(前の2つの形式のいずれとも一致しないもの)が許可されます。ディレクティブの行の後の前処理トークンは、通常のテキストと同様に処理されます(現在マクロ名として定義されている各識別子は、その前処理トークンの置換リストで置換されます)。すべての置き換えの後に生じる指令は、前の2つの形式のうちの1つと一致しなければならず、その後、適切に処理されます。

EXAMPLE 1 #include 前処理ディレクティブの最も一般的な使い方は以下の通りです。
#include <stdio.h>
#include "myprog.h"
EXAMPLE 2 マクロで置換された#includeディレクティブの例です。
#if VERSION == 1
    #define INCFILE "vers1.h"
#elif VERSION == 2
    #define INCFILE "vers2.h" // and so on
#else
    #define INCFILE "versN.h"
#endif
#include INCFILE

前方参照:マクロの置き換え(6.10.3)

インクルードガード

[編集]

インクルードガードとは、複数回ヘッダーをインクルードすることを防止する方法です。 インクルードガードの記述は次のようになっている。

#ifndef インクルードガード用の識別子
#define インクルードガード用の識別子
/*
ソースコード
*/
#endif

このヘッダーをインクルードする際、 2回目以降は「インクルードガード用の識別子」が定義されているため、 ソースコードが読み飛ばされる。

また、コンパイラによっては次のようなインクルードガードの記述もある。

#pragma once

マクロ置き換え

[編集]

マクロ置き換えとは、マクロ名を置換要素並びで置き換える前処理指令です[10]。 マクロ置き換えには、オブジェクト形式マクロと関数形式マクロがある。

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

次の形式の前処理指令をオブジェクト形式マクロと呼ぶ。

形式
    # define identifier replacement-list new-line

defineの直後に記述してある識別子をマクロ名( object-like macro )という。 オブジェクト形式マクロ( object-like macro )は、 これ以降のマクロ名を置換要素並びで置き換える。

  • 関数形式マクロ

次の形式の前処理指令を関数形式マクロ( function-like macro )と呼ぶ。

形式
    # define identifier lparen identifier-listopt ) replacement-list new-line
    # define identifier lparen ... ) replacement-list new-line
    # define identifier lparen identifier-list , ... ) replacement-list new-line

識別子並びは省略可能で、仮引数を指定し、個々の仮引数は「,」で区切り、最後に省略記号「...」を指定してもよい。 関数形式マクロは、 これ以降のマクロ名とそれに続く「(」からそれに対応する「)」までを、 置換要素並びで置き換える(マクロ呼出し)。


実引数置換

[編集]

実引数置換とは、関数形式マクロの実引数を識別した後行われ、実引数の中に含まれるすべてのマクロの展開後、置換要素並びの中の仮引数を対応する実引数で置き換える[11]。 ただし、#前処理字句または##前処理字句が前にある仮引数と、##前処理字句が後に続く仮引数とは除く。 実引数置換の前に、実引数の前処理字句列を完全にマクロ置き換えする。 このとき、実引数ごとに、その前処理字句列が、現在の前処理ファイルの残りとなっているものとみなして処理する。 つまり、他の前処理字句列が存在しないかのように扱われる。

置換要素並びの中に現れる識別子__VA_ARGS__は、それが一つの仮引数であるかのように扱われなければならない。 それを、可変個数の実引数が形成する前処理字句列で置き換える。

#演算子

[編集]
  1. 演算子は、文字列化演算子と呼ばれ、関数形式マクロの置換要素並びの中の仮引数の直前に付けることができ、#前処理字句と仮引数を、実引数を「"」で囲んだ単純文字列リテラルで置き換える[12]

その際、「"」文字及び「\」文字の前に、「\」文字が挿入される。


##演算子

[編集]
    1. 演算子は、トークン連結演算子と呼ばれ、オブジェクト形式マクロ又は関数形式マクロの置換要素並びの中で使われ、その直前にある字句とその直後にある字句を連結する[13]

関数形式マクロの置換要素並びの中で、仮引数の直前又は直後に##前処理字句がある場合、その仮引数を対応する実引数で置き換える。

再走査と再置き換え

[編集]

実引数置換、#演算子及び##演算子の処理、プレースマーカー前処理字句の削除を行った後、さらに置き換えるべきマクロ名があるかどうかを調べるために、ソースファイル上のその後のすべての前処理字句とともにその結果の前処理字句を再走査する[14]

現在置き換え中のマクロの名前を置換要素並びのこの走査中に検出した場合や入れ子になった置き換えで現在置き換え中のマクロの名前を検出した場合は、置き換えは行わない。

完全にマクロ置き換えした結果の前処理字句列は、前処理指令の形をしていたとしても、前処理指令として処理することはない。

マクロ定義の有効範囲

[編集]

マクロ定義の有効範囲は、そのマクロ定義から、対応する#undef指令を検出するまで又は前処理翻訳単位の最後までです[15]

マクロ定義を無効にするには、次のように記述する。

#undef 識別子

識別子で無効にしたいマクロ名を指定する。

行制御

[編集]

行制御とは、この指令の次のソース行の行番号を指定する前処理指令です[16]。 行制御の記述は、次の2通りがある。

#line 数字列

この指令の次のソース行の行番号が、数字列で指定された行番号となる。 数字列は1以上2,147,483,647[17]以下の10進整数でなければならない。

#line 数字列 "s文字列"

この指令は、同様に行番号を設定し、s文字列でソースファイル名を置き換える。

また、次の形式の行制御の前処理指令もある。

#line 前処理字句列

この形式の前処理字句列は、 マクロ置き換えで、上の2通りの形式のいずれかと一致せねばならず、 一致した形式の規則に従って処理する。

エラー指令

[編集]

エラー指令とは、処理系に対し、指定された前処理字句の列を含む診断メッセージを出力する前処理指令です[18]。 エラー指令の記述は次のようになっている。

#error 前処理字句列

前処理字句列で出力する診断メッセージを指示する。

プラグマ指令

[編集]

プラグマ指令( Pragma directive )は、以下のような形式をしています[19]

形式
# pragma pp-tokensopt new-line
pragma の直後の前処理トークン( preprocessing toke )が STDC が ではない場合(マクロ置換の前)は、実装が定義した方法で動作します。
このような動作は、翻訳の失敗や、翻訳者や結果としてのプログラムの動作を不適合にする可能性があります。
実装で認識されていないプラグマは無視されます。
前処理トークンである STDC が pragma の直後にある場合(マクロ置換の前)は、指令のマクロ置換は行われず、指令は次のような形になります。
意味については別述。
standard-pragma:
    # pragma STDC FP_CONTRACT on-off-switch
    # pragma STDC FENV_ACCESS on-off-switch
    # pragma STDC FENV_DEC_ROUND dec-direction
    # pragma STDC FENV_ROUND direction
    # pragma STDC CX_LIMITED_RANGE on-off-switch
on-off-switch: one of
    ON OFF DEFAULT
direction: one of
    FE_DOWNWARD FE_TONEAREST FE_TONEARESTFROMZERO FE_TOWARDZERO FE_UPWARD FE_DYNAMIC
dec-direction: one of
    FE_DEC_DOWNWARD FE_DEC_TONEAREST FE_DEC_TONEARESTFROMZERO FE_DEC_TOWARDZERO FE_DEC_UPWARD FE_DEC_DYNAMIC


空指令

[編集]

空指令とは、何の効果もない前処理指令です。 空指令の記述は次のようになっている。

#

[20]

事前定義済みマクロ定数

[編集]

この節は書きかけです。この節を編集してくれる方を心からお待ちしています。

事前定義済みマクロ定数がある[21][22][23]

以下のサブクラスに記載されている定義済みマクロの値は、翻訳単位全体で一定です(ただし、__FILE__ と __LINE__ を除く[24][23]

これらのマクロ名および定義された識別子は、#define または #undef 前処理指令の対象になってはなりません。その他の定義済みマクロ名は、先頭にアンダースコアを置き、その後に大文字または2つ目のアンダースコアを置きます[23]

実装では、マクロ __cplusplus を事前に定義してはならず、また、標準のヘッダーでも定義してはならない[23]

必須マクロ

[編集]

以下のマクロ名は、実装によって定義されるものとする[25]

__DATE__
前処理翻訳ユニットの翻訳日:"Mmm dd yyyy "形式の文字
ここで、月の名前はasctime関数で生成されたものと同じであり、ddの最初の文字は、その値が10未満の場合はスペース文字です。
翻訳の日付が得られない場合は、実装で定義された有効な日付を供給しなければならない。
__FILE__
現在のソースファイルの推定名(文字列リテラル)
__LINE__
現在のソース行の(現在のソースファイル内の)推定行番号(整数定数)
__STDC__
適合する実装であることを示すための整数定数 1。
__STDC_HOSTED__
ホスト実装の場合
整数定数 1
そうでない場合(=フリースタンディング実装である場合)
整数定数 0
__STDC_VERSION__
準拠する仕様に応じた整数定数
C90
未定義
C95
199409L
C99
199901L
C11
201112L
C17
201710L
__TIME__
前処理翻訳ユニットの翻訳時刻:文字列リテラル
asctime関数で生成された時間と同様に、"hh:mm:ss" 形式の文字列リテラル。
翻訳時刻が得られない場合は、実装で定義された有効な時刻を提供する。
コード例
#include <stdio.h>
int main(void){
#ifdef __DATE__
    printf("__DATE__ = %s\n", __DATE__);
#else
    printf("defined(__DATE__) == 0");
#endif
#ifdef __FILE__
    printf("__FILE__ = %s\n", __FILE__);
#else
    printf("defined(__FILE__) == 0");
#endif
#ifdef __LINE__
    printf("__LINE__ = %d\n", __LINE__);
#else
    printf("defined(__LINE__) == 0");
#endif
#ifdef __STDC__
    printf("__STDC__ = %d\n", __STDC__);
#else
    printf("defined(__STDC__) == 0");
#endif
#ifdef __STDC_HOSTED__
    printf("__STDC_HOSTED__ = %d\n", __STDC_HOSTED__);
#else
    printf("defined(__STDC_HOSTED__) == 0");
#endif
#ifdef __STDC_VERSION__
    printf("__STDC_VERSION__ = %ld\n", __STDC_VERSION__);
#else
    printf("defined(__STDC_VERSION__) == 0");
#endif
#ifdef __TIME__
    printf("__TIME__ = %s\n", __TIME__);
#else
    printf("defined(__TIME__) == 0");
#endif
}
結果(paiza.io /language=c)
__DATE__ = Aug  6 2021
__FILE__ = Main.c
__LINE__ = 15
__STDC__ = 1
__STDC_HOSTED__ = 1
__STDC_VERSION__ = 201710
__TIME__ = 23:45:08
結果(Visual Studio 2017 /std:c17 /Windows 10)
__DATE__ = Aug  7 2021
__FILE__ = C:\Users\user1\Source\Repos\macros\macros.c
__LINE__ = 14
defined(__STDC__) == 0
__STDC_HOSTED__ = 1
__STDC_VERSION__ = 201710
__TIME__ = 08:54:00
結果(clang11/FreeBSD13)
__DATE__ = Aug  7 2021
__FILE__ = macros.c
__LINE__ = 14
__STDC__ = 1
__STDC_HOSTED__ = 1
__STDC_VERSION__ = 201710
__TIME__ = 08:59:18

環境マクロ

[編集]

以下のマクロ名は、実装によって条件付きで定義されています[26]

__STDC_ISO_10646__
__STDC_MB_MIGHT_NEQ_WC__
__STDC_UTF_16__
__STDC_UTF_32__

条件付き機能マクロ

[編集]

以下のマクロ名は、実装によって条件付きで定義されます[27]

__STDC_ANALYZABLE__
__STDC_IEC_559__
__STDC_IEC_559_COMPLEX__
__STDC_LIB_EXT1__
__STDC_NO_ATOMICS__
__STDC_NO_COMPLEX__
__STDC_NO_THREADS__
__STDC_NO_VLA__

__STDC_NO_COMPLEX__ を定義する実装は、 __STDC_IEC_559_COMPLEX__ を定義してはならない。

事前定義済みマクロ定数一覧

[編集]
事前定義済みマクロ定数一覧
種別 マクロ名 意味
必須マクロ __DATE__ 前処理翻訳単位の翻訳の日付("Mmm dd yyyy"の形式をもつ単純文字列リテラル)
__FILE__ ソースファイル名(単純文字列リテラル)
__LINE__ 現在のソース行の行番号(整数定数)
__STDC__ 整数定数1.規格合致処理系であることを示す。
__STDC_HOSTED__ 処理系が規格合致ホスト処理系の場合、整数定数1。そうでない場合(つまり、フリースタンディング環境である場合)、(未定義ではなく)整数定数0。
__STDC_VERSION__ 標準Cのバージョンを表す値(C95 では 199409L、C99 では 199901L、C11 では 201112L、C90 では定義されていない)。このマクロが定義されているか否か、および、定義されている場合の値は実装依存です。
__TIME__ 前処理翻訳単位の翻訳の時刻。("hh:mm:ss"の形式の単純文字列リテラル)
環境マクロ __STDC_ISO_10646__ 型wchar_tの値が、ISO/IEC 10646(UCS; Universal Coded Character Set)で定義された文字の符号化表現をもつことを示すためのyyyymmLの形式の整数定数。
__STDC_MB_MIGHT_NEQ_WC__
__STDC_UTF_16__
__STDC_UTF_32__
条件付き機能マクロ __STDC_ANALYZABLE__
__STDC_IEC_559__ IEC 60559浮動小数点仕様に準拠している場合に定義される。ISO/IEC 9899:1999(C99)以降で定義される。
__STDC_IEC_559_COMPLEX__ IEC 60559互換の複素数仕様に準拠している場合に定義される。ISO/IEC 9899:1999(C99)以降で定義される[28]
__STDC_LIB_EXT1__
__STDC_NO_ATOMICS__
__STDC_NO_COMPLEX__
__STDC_NO_THREADS__
__STDC_NO_VLA__

※ __DATE__と__TIME__はそれを使わなければ絶対に解決できない課題を解決するためにのみ使うべきであり、それ以外の場合に安易に使うべきではない。特に、バージョン値の代用としての使用は不適切です。 [29]

プラグマ演算子

[編集]

プラグマ演算子は、指定した文字列リテラルを文字列解除し、その結果をプラグマ指令の中の前処理字句列として実行する[30]。 つまり、次の形式の指令は、その次の形式でも表現できる。

#pragma listing on "..\listing.dir"
_Pragma("listing on \"..\\listing.dir\"")

脚註

[編集]
  1. ^ N3096 working draft — April 1, 2023 ISO/IEC 9899:2023 (E). ISO/IEC JTC1/SC22/WG14. p. 162, §6.10 Preprocessing directives. http://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf. 
  2. ^ N2596 working draft — December 11, 2020 ISO/IEC 9899:202x (E). ISO/IEC JTC1/SC22/WG14. p. 134です。 §6.10.1 Conditional inclusion. http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2596.pdf. 
  3. ^ 『JISX3010:2003』p.112「6.10.1 条件付き取り込み」
  4. ^ この未定義の識別子を 0 と解釈する挙動のため、識別子のミススペルがあたかも 0 を定義しているように見える事による発見困難なバグの原因になります。⇒ #未定義マクロの値
  5. ^ §6.4.8 Preprocessing numbers
  6. ^ C11: WG14/N1570 Committee Draft — April 12, 2011 ISO/IEC 9899:201x. ISO/IEC. p. 162, §6.10.1 Conditional inclusion. http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf. 
  7. ^ N2596 working draft — December 11, 2020 ISO/IEC 9899:202x (E). ISO/IEC JTC1/SC22/WG14. p. 136, §6.10.2 Source file inclusion. http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2596.pdf. 
  8. ^ 『JISX3010:2003』p.113「6.10.2 ソースファイル取り込み」
  9. ^ 標準ヘッダー(stdio.hなど)を、#include "ヘッダー名"の形式で取り込む事は、重大なセキュリティホールとなり得るので、厳に慎むべきです。
  10. ^ 『JISX3010:2003』p.114「6.10.3 マクロ置き換え」
  11. ^ 『JISX3010:2003』p.116「6.10.3.1 実引数置換」
  12. ^ 『JISX3010:2003』p.116「6.10.3.2 #演算子」
  13. ^ 『JISX3010:2003』p.116「6.10.3.3 ##演算子」
  14. ^ 『JISX3010:2003』p.117「6.10.3.4 再走査と再置き換え」
  15. ^ 『JISX3010:2003』p.117「6.10.3.5 マクロ定義の有効範囲」
  16. ^ 『JISX3010:2003』p.120「6.10.4 行制御」
  17. ^ C99より前は、32,767
  18. ^ 『JISX3010:2003』p.121「6.10.5 エラー指令」
  19. ^ N2596 working draft — December 11, 2020 ISO/IEC 9899:202x (E). ISO/IEC JTC1/SC22/WG14. p. 144, §6.10.6 Pragma directive. http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2596.pdf. 
  20. ^ 『JISX3010:2003』p.121「6.10.7 空指令」
  21. ^ N1653 Working draft changes for C99 preprocessor synchronization
  22. ^ CWG Issue 630. Equality of narrow and wide character values in the basic character set
  23. ^ 23.0 23.1 23.2 23.3 C11: WG14/N1570 Committee Draft — April 12, 2011 ISO/IEC 9899:201x. ISO/IEC. p. 175, §6.10.8 Predefined macro names. http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf. 
  24. ^ __LINE__ はともかく、__FILE__ は翻訳単位全体に一定では?との当然の疑問がありますが、#line でファイル名を指令された場合に変わりえます。
  25. ^ C11: WG14/N1570 Committee Draft — April 12, 2011 ISO/IEC 9899:201x. ISO/IEC. p. 175, §6.10.8.1 Mandatory macros. http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf. 
  26. ^ C11: WG14/N1570 Committee Draft — April 12, 2011 ISO/IEC 9899:201x. ISO/IEC. p. 176, §6.10.8.2 Environment macros. http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf. 
  27. ^ C11: WG14/N1570 Committee Draft — April 12, 2011 ISO/IEC 9899:201x. ISO/IEC. p. 177, §6.10.8.3 Conditional feature macros. http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf. 
  28. ^ __STDC_NO_COMPLEX__ を定義する実装は、 __STDC_IEC_559_COMPLEX__ を定義してはならない。
  29. ^ 『JISX3010:2003』p.121「6.10.8 あらかじめ定義されたマクロ名」
  30. ^ 『JISX3010:2003』p.122「6.10.9 プラグマ演算子」

参考文献

[編集]
  • 日本工業標準調査会(当時、現:日本産業標準調査会)『JISX3010 プログラム言語C』2003年12月20日改正