「C言語/前処理指令」の版間の差分

削除された内容 追加された内容
Ef3 (トーク | 投稿記録)
タグ: 2017年版ソースエディター
Ef3 (トーク | 投稿記録)
訳の手直し。s/ヘッダーファイル/ヘッダー/g
タグ: 2017年版ソースエディター
89 行
 
識別子(キーワードと同一のものを含む)は以下のように解釈されます。
;形式:<pre>
defined ''identifier''
</pre>または<pre>
defined ( ''identifier'' )
; </pre>識別子がマクロ名として現在定義されている場合 (つまり、定義済みであるか、同じ識別子を持つ #undef 指令を介さずに #define 前処理指令の対象となっている場合)、1 に評価され、そうでない場合は 0 に評価されます。
:条件付包含式( conditional inclusion expression )は、以下の形式の単項演算子式を含むことができます。<pre>
: 定義済みであるか、#undefine が介在しない #define 前処理指令の対象となっている場合
: 1 に評価されます。
; 識別子がマクロ名として定義されている場合
:定義済みであるか、同じ識別子を持つ#undef指令の対象となっている場合
: 0 に評価されます。
条件付包含式( conditional inclusion expression )は、以下の形式の単項演算子式を含むことができます。
__has_c_attribute ( ''pp-tokens'' )
</pre>れらの演算子式です。前処理トークン、pp-tokens を属性トークンとして解釈して指定された名前の属性を実装がサポートしている場合はです。整数定数の形式に一致する0でないpp-numberで置き換えられです。そうでない場合は0で置き換えられます前処理トークンpp-tokens属性トークンの形式一致しなければなりませんらない
:すべてのマクロ置換が行われた後に(制御式となる前処理トークンのリストに)残る各前処理トークンは、トークンの語彙形式でなければならない(6(§ 6.4)。
 
;セマンティクス
すべてのマクロ置換が行われた後に(制御式となる前処理トークンのリストに)残る各前処理トークンは、トークンの語彙形式でなければならない(6.4)。
:また、#ifdef、#ifndef、および定義済み条件付き包含演算子は、 __has_c_attribute を定義済みマクロの名前であるかのように扱うものとします。識別子 __has_c_attribute は、本節で言及されていないいかなる文脈にも登場してはなりません。
 
:以下の形式の前処理用ディレクティブ<pre>
また、#ifdef、#ifndef、および定義済み条件付き包含演算子は、 __has_c_attribute を定義済みマクロの名前であるかのように扱うものとします。識別子 __has_c_attribute は、本節で言及されていないいかなる文脈にも登場してはなりません。
# elifif ''constant-expressionidentifier'' ''new-line'' ''group''<sub>opt</sub>
;形式
# ifelif ''constant-expressionidentifier'' ''new-line'' ''group''<sub>opt</sub>
</pre>という形式の前処理指令は、制御する定数式の評価値がゼロ以外ない評価されるかどうかをチェックします。
# elif ''constant-expression'' ''new-line'' ''group''<sub>opt</sub>
:評価の前に、制御する定数式となる前処理トークンのリスト内のマクロ呼び出しは、通常のテキストと同様に置き換えられます(定義された単項演算子によって変更されたマクロ名を除く)。この置換処理の結果として定義されたトークンが生成されたり、定義された単項演算子の使用がマクロ置換前の 2 つの指定された形式のうちの 1 つと一致しない場合、その動作は未定義です。マクロの展開とdefinedおよび__has_c_attribute単項演算子の評価によるすべての置き換えが行われた後、残りのすべての識別子(キーワードと語彙的に同一のものを含む)がpp-number 0に置き換えられ<ref>この未定義の識別子を 0 と解釈する挙動のため、識別子のミススペルがあたかも 0 を定義しているように見える事による発見困難なバグの原因になります。⇒ [[#未定義マクロの値]]</ref>、その後、各前処理トークンがトークンに変換されます。結果のトークンは、6.6の規則に従って評価される制御定数式を構成します。このトークンの変換と評価のために,すべての符号付き整数型とすべての符号なし整数型は,それぞれヘッダー<stdint.h>で定義されているintmax_t型とuintmax_t型と同じ表現を持っているかのように振る舞います。これには、文字定数の解釈も含まれており、エスケープシーケンスを実行文字セットのメンバーに変換する必要がある場合もあります。これらの文字定数の数値が、同一の文字定数が式の中(#ifや#elif指令の中を除く)に現れたときに得られる値と一致するかどうかは、実装で定義されます。また、1文字の文字定数が負の値を持つことができるかどうかは、実装で定義される。
制御する定数式の評価値がゼロでないかどうかをチェックします。
:以下の形式の前処理用ディレクティブ<pre>
 
# ifdef ''constant-expression'' ''new-line'' ''group''<sub>opt</sub>
評価の前に、制御する定数式となる前処理トークンのリスト内のマクロ呼び出しは、通常のテキストと同様に置き換えられます(定義された単項演算子によって修正されたマクロ名を除く)。
# ifndef ''constant-expression'' ''new-line'' ''group''<sub>opt</sub>
 
</pre>は、識別子がマクロ名として現在定義されているかどうかをチェックする。これらの条件は、それぞれ''' #if defined identifier''' および '''#if !defined identifier''' と同じです。
この置換処理の結果として定義されたトークンが生成されたり、定義された単項演算子の使用がマクロ置換前の 2 つの指定された形式のうちの 1 つと一致しない場合、その動作は未定義です。
: 各ディレクティブの条件は、順にチェックされます。入れ子になっている条件式のレベルを把握するために、指令は指令を決定する名前のみで処理され、残りの指令の前処理トークンは無視され、グループ内の他の前処理トークンも無視されます。制御条件が真(0以外)と評価された最初のグループだけが処理され、それ以降のグループはスキップされ、その制御指令はスキップされたグループに含まれているかのように処理されます。どの条件も真と評価されず、'''#else''' ディレクティブがある場合は、'''#else''' で制御されるグループが処理されます。'''#else''' ディレクティブがない場合は、'''#endif''' までのすべてのグループがスキップされます。
 
:例<source lang=c>
マクロの展開とdefinedおよび__has_c_attribute単項演算子の評価によるすべての置き換えが実行された後、残りのすべての識別子(キーワードと語彙的に同一のものを含む)がpp-number 0に置き換えられ、その後、各前処理トークンがトークンに変換されます<ref>この未定義の識別子を 0 と解釈する挙動のため、識別子のミススペルがあたかも 0 を定義しているように見える事による発見困難なバグの原因になります。⇒ [[#未定義マクロの値]]</ref>。
/* Fallback for compilers not yet implementing this feature. */
 
#ifndef __has_c_attribute
結果のトークンは、6.6の規則に従って評価される制御定数式を構成します。
#define __has_c_attribute(x) 0
 
#endif /*
このトークンの変換と評価のために、すべての符号付き整数型とすべての符号なし整数型は、それぞれヘッダーの<stdint.h>で定義されているintmax_t型とuintmax_t型と同じ表現を持っているかのように動作します。
__has_c_attribute */
 
#if __has_c_attribute(fallthrough)
これには、文字定数の解釈も含まれており、エスケープシーケンスを実行文字セットのメンバーに変換する必要がある場合もあります。これらの文字定数の数値が、同じ文字定数が式の中(#ifや#elif命令の中を除く)に出現したときの値と一致するかどうかは、実装によって決まります。
/* 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
</source>
前方参照:マクロの置換(6.10.3)、ソースファイルのインクルード(6.10.2)、最大の整数型
 
=== 未定義マクロの値 ===
137 ⟶ 141行目:
| page = 136, §6.10.2 ''Source file inclusion''
| publisher = [http://www.open-std.org/jtc1/sc22/wg14/www/projects ISO/IEC JTC1/SC22/WG14]}}</ref><ref>『JISX3010:2003』p.113「6.10.2 ソースファイル取り込み」</ref>。
;制約
:'''#include''' ディレクティブは、インプリメンテーションによって処理可能なヘッダーまたはソースファイルを特定するものです。
;セマンティクス
 
:以下の形式の前処理用ディレクティブ<pre>
;形式
# include < ''h-char-sequence'' > ''new-line''
</pre>この形式は、実装で定義されている一連の場所を検索して、 < と > の間の指定された順序で一意に識別されるヘッダを探し、 そのディレクティブをヘッダの内容全体で置き換える。どのように場所を指定するか、どのようにヘッダを特定するかは、実装で定義されます。
:以下の形式の前処理用ディレクティブ<pre>
# include " ''q-char-sequence'' " ''new-line''
この形式</pre>は、" デリミタ "の間の指定された順序で特定されるソースファイルの内容全体で、その指示を置き換えます。指定されたソースファイルは、実装で定義された方法で検索されます。この検索がサポートされていない場合や、検索に失敗した場合は、次のようにヘッダーファイルが読ま書かているかのように、指令が再処理されます。<pre>
 
ヘッダーファイルのインクルード
# include < ''h-char-sequence'' > ''new-line''
</pre>は、元の指令ディレクティブと同じ内容含まれたシーケンス(>文字がもしあればそれも > 文字を含む)に変更しで置き換えられます<ref>標準ヘッダーファイル(stdio.hなど)を、<syntaxhighlight lang=c inline>#include "ヘッダーファイル名"</syntaxhighlight>の形式で取り込む事は、重大なセキュリティホールとなり得るので、厳に慎むべきです。</ref>。
この形式は、実装で定義されている一連の場所を検索して、 < と > の間の指定された順序で一意に識別されるヘッダを探し、 そのディレクティブをヘッダの内容全体で置き換える。どのように場所を指定するか、どのようにヘッダを特定するかは、実装で定義されます。
:以下の形式の前処理用ディレクティブ<pre>
 
ソースファイルのインクルード
# include " ''q-char-sequence'' " ''new-line''
この形式は、" デリミタ "の間の指定された順序で特定されるソースファイルの内容全体で、その指示を置き換えます。指定されたソースファイルは、実装で定義された方法で検索されます。この検索がサポートされていない場合や、検索に失敗した場合は、次のようにヘッダーファイルが読まれたかのように再処理されます。
 
# include < ''h-char-sequence'' > ''new-line''
 
を、元の指令と同一の含まれたシーケンス(>文字があればそれも含む)に変更します<ref>標準ヘッダーファイル(stdio.hなど)を、<syntaxhighlight lang=c inline>#include "ヘッダーファイル名"</syntaxhighlight>の形式で取り込む事は、重大なセキュリティホールとなり得るので、厳に慎むべきです。</ref>。
 
# include ''pp-tokens'' ''new-line''
</pre>(前の2つの形式のいずれも一致しないもの)許可されています。ディレクティブの include の後の前処理トークンは、通常のテキストと同様に処理されます。(現在マクロ名として定義されている各識別子は、その前処理トークンの置換リストで置換されます)。すべての置えのに生じる指令は、前の2つの形式のいずれかにうちの1つと一致しなければならない。<と>ず、そ前処理トークンのペアまたは"と"の前適切に処理トークンを1つのヘッダー名の前処理トークンにまとめる方法は、実装で定義されます
 
:;EXAMPLE 1 #include 前処理ディレクティブの最も一般的な使い方は以下の通りです。:<source lang=c>
(前の二つの形式のいずれにも一致しないもの)は許可されています。ディレクティブの include の後の前処理トークンは、通常のテキストと同様に処理されます。(現在マクロ名として定義されている各識別子は、その前処理トークンの置換リストで置換されます)。すべての置換後の指令は、前の2つの形式のいずれかに一致しなければならない。<と>の前処理トークンのペアまたは、"と"の前処理トークンを1つのヘッダー名の前処理トークンにまとめる方法は、実装で定義される。
#include <stdio.h>
#include "myprog.h"
</source>
:;EXAMPLE 2 マクロで置換された#includeディレクティブの例です。:<source lang=c>
#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
</source>
前方参照:マクロの置き換え(6.10.3)
 
=== インクルードガード ===
インクルードガードとは、複数回ヘッダファイルをインクルードすることを防止する方法です。
インクルードガードの記述は次のようになっている。
 
170 ⟶ 184行目:
#endif
</syntaxhighlight>
このヘッダファイルをインクルードする際、
2回目以降は「インクルードガード用の識別子」が定義されているため、
ソースコードが読み飛ばされる。