条件付きコンパイル
条件付きコンパイルとは、どのコードをコンパイルし、どのコードをコンパイルしないかを選択するプロセスである。 どのコードをコンパイルし、どのコードをコンパイルしないかを選択するプロセスである。
ConditionalDeclaration: Condition DeclarationBlock Condition DeclarationBlock else DeclarationBlock Condition : DeclDefsopt Condition DeclarationBlock else : DeclDefsopt ConditionalStatement: Condition NoScopeNonEmptyStatement Condition NoScopeNonEmptyStatement else NoScopeNonEmptyStatement
条件が満たされていれば、次のようになる。 DeclarationBlockまたはStatementがコンパイルされる。 条件を満たさない場合は、次の宣言ブロックまたは文がコンパイルされる。 else がコンパイルされる。
コンパイルされないDeclarationBlockまたはStatementは、構文的に正しくなければならない。 は、構文的に正しくなければならない。
たとえ 新しいスコープは導入されない。 が{ } 。
条件付き宣言と 条件付きステートメント は入れ子にすることができる。
StaticAssertは を使うと、コンパイル時にエラーとなる条件分岐に対してエラーを出すことができる。 コンパイル時にエラーを発行することができる。
条件には以下の形式がある:
Condition: VersionCondition DebugCondition StaticIfCondition
バージョン条件
VersionCondition: version ( Identifier ) version ( unittest ) version ( assert )
バージョンは、あるモジュールの複数のバージョンを1つのソースファイル を実装できるようにする。
VersionConditionは、Identifier がバージョン識別子と一致する場合に満たされる。
バージョン識別子は、コマンドラインで。 -version で設定するか、モジュール自体に またはコンパイラによって定義される。 またはコンパイラーによって定義される。
バージョン識別子は独自の名前空間内にあり、デバッグ識別子や他の名前空間と衝突しない。 デバッグ識別子やモジュール内の他のシンボルと衝突しない。 あるモジュールで定義されたバージョン識別子は、インポートされた他のモジュールに影響を与えない。 あるモジュールで定義されたバージョン識別子は、他のインポートされたモジュールには影響しない。
int k; version (Demo) // デモ版では、このコードブロックでコンパイルする { int i; int k; // エラー、kはすでに定義されている i = 3; } x = i; // 上記で宣言したiを使用する
version (X86) { ... // カスタム・インラインアセンブラを実装する } else { ... // デフォルトの遅いバージョンを使う }
version(unittest) 。 コードがユニットテストを有効にしてコンパイルされている場合にのみ( の -unittestdmd のオプション)を有効にしてコンパイルした場合にのみ満たされる。
バージョン仕様
VersionSpecification: version = Identifier ;
バージョン指定は、次のように機能セットを1つのメジャーバージョンにまとめることを容易にする。 を1つのメジャーバージョンにまとめることができる:
version (ProfessionalEdition) { version = FeatureA; version = FeatureB; version = FeatureC; } version (HomeEdition) { version = FeatureA; } ... version (FeatureB) { ... implement Feature B ... }
バージョン識別子やレベルは、前方参照できない:
version (Foo) { int x; } version = Foo; // エラー、Fooはすでに使用されている
VersionSpecificationsは、モジュール・スコープでのみ使用できる。
デバッグ条件とバージョン条件は、表面的には同じ動作をする。 表面的には同じ動作をする、 その目的はまったく異なる。デバッグ文 は、リリース・バージョンでは削除されるデバッグ・コードを追加するためのものだ。 バージョン・ステートメントは、移植性と複数のリリース・バージョンを支援するためのものである。 バージョンをサポートするためのものだ。
以下は、フルバージョンの例である。 フルバージョンの例だ:
class Foo { int a, b; version(full) { int extrafunctionality() { ... return 1; // 追加関数がサポートされている } } else // デモ { int extrafunctionality() { return 0; // 余分な関数はサポートされていない } } }
様々な異なるバージョンのビルドは、パラメータ をバージョンに指定する:
version(identifier) // バージョン・キーワードが識別子の場合、 // バージョン・コードを追加する { ... version code ... }
これはおそらく、コマンドラインから -version=identifier.
定義済みバージョン
いくつかの環境バージョン識別子と識別子 の名前空間は、一貫した使い方のためにあらかじめ定義されている。 バージョン識別子はコード内の他の識別子と衝突しない。 別の名前空間にある。 定義済みのバージョン識別子はグローバルである。 すなわち、コンパイルおよびインポートされるすべてのモジュールに適用される。
Version Identifier | Description |
---|---|
DigitalMars | DMD (Digital Mars D)はコンパイラである。 |
GNU | GDC (GNU D Compiler) はコンパイラーである。 |
LDC | LDC (LLVM D Compiler) はコンパイラである。 |
SDC | SDC (Stupid D Compiler) はコンパイラである。 |
Windows | マイクロソフトのWindowsシステム |
Win32 | マイクロソフト32ビットWindowsシステム |
Win64 | マイクロソフト64ビットWindowsシステム |
linux | すべてのLinuxシステム |
OSX | macOS |
iOS | iOS |
TVOS | tvOS |
WatchOS | watchOS |
VisionOS | visionOS |
FreeBSD | FreeBSD |
OpenBSD | OpenBSD |
NetBSD | NetBSD |
DragonFlyBSD | ドラゴンフライBSD |
BSD | その他すべてのBSD |
Solaris | ソラリス |
Posix | すべてのPOSIXシステム(Linux、FreeBSD、OS X、Solarisなどを含む) |
AIX | IBMアドバンスト・インタラクティブeXecutive OS |
Haiku | Haikuオペレーティング・システム |
SkyOS | SkyOSオペレーティング・システム |
SysV3 | システムVリリース3 |
SysV4 | System V リリース4 |
Hurd | GNU Hurd |
Android | Androidプラットフォーム |
Emscripten | Emscriptenプラットフォーム |
PlayStation | PlayStationプラットフォーム |
PlayStation4 | PlayStation 4プラットフォーム |
Cygwin | Cygwin環境 |
MinGW | MinGW環境 |
FreeStanding | オペレーティングシステムのない環境(ベアメタルターゲットなど) |
CRuntime_Bionic | Bionic Cランタイム |
CRuntime_DigitalMars | DigitalMars Cランタイム |
CRuntime_Glibc | Glibc Cランタイム |
CRuntime_Microsoft | Microsoft Cランタイム |
CRuntime_Musl | musl Cランタイム |
CRuntime_Newlib | newlib Cランタイム |
CRuntime_UClibc | uClibc Cランタイム |
CRuntime_WASI | WASI Cランタイム |
CppRuntime_Clang | Clang Cppランタイム |
CppRuntime_DigitalMars | DigitalMars Cppランタイム |
CppRuntime_Gcc | Gcc Cppランタイム |
CppRuntime_Microsoft | Microsoft Cppランタイム |
CppRuntime_Sun | Sun Cppランタイム |
X86 | インテルおよびAMD 32ビットプロセッサー |
X86_64 | インテルおよびAMD 64ビットプロセッサー |
ARM | ARMアーキテクチャ(32ビット)(AArch32など) |
ARM_Thumb | あらゆるThumbモードのARM |
ARM_SoftFloat | ARMsoft 浮動小数点 ABI |
ARM_SoftFP | ARMsoftfp 浮動小数点 ABI |
ARM_HardFloat | ARMhardfp 浮動小数点 ABI |
AArch64 | Advanced RISC Machineアーキテクチャ(64ビット) |
AsmJS | 中間プログラミング言語 asm.js |
AVR | 8 ビット Atmel AVR マイクロコントローラー |
Epiphany | Epiphany アーキテクチャ |
PPC | PowerPCアーキテクチャ(32ビット |
PPC_SoftFloat | PowerPCソフトフロートABI |
PPC_HardFloat | PowerPCハードフロートABI |
PPC64 | PowerPCアーキテクチャ、64ビット |
IA64 | Itaniumアーキテクチャ(64ビット) |
MIPS32 | MIPSアーキテクチャ、32ビット |
MIPS64 | MIPSアーキテクチャ、64ビット |
MIPS_O32 | MIPS O32 ABI |
MIPS_N32 | MIPS N32 ABI |
MIPS_O64 | MIPS O64 ABI |
MIPS_N64 | MIPS N64 ABI |
MIPS_EABI | MIPS EABI |
MIPS_SoftFloat | MIPSsoft-float ABI |
MIPS_HardFloat | MIPShard-float ABI |
MSP430 | MSP430アーキテクチャ |
NVPTX | Nvidia並列スレッド実行(PTX)アーキテクチャ、32ビット |
NVPTX64 | Nvidia並列スレッド実行(PTX)アーキテクチャ、64ビット |
RISCV32 | RISC-Vアーキテクチャ、32ビット |
RISCV64 | RISC-Vアーキテクチャ、64ビット |
SPARC | SPARCアーキテクチャ、32ビット |
SPARC_V8Plus | SPARC v8+ ABI |
SPARC_SoftFloat | SPARCソフトフロートABI |
SPARC_HardFloat | SPARCハードフロートABI |
SPARC64 | SPARCアーキテクチャ、64ビット |
S390 | System/390アーキテクチャ、32ビット |
SystemZ | System Zアーキテクチャ、64ビット |
HPPA | HP PA-RISCアーキテクチャ、32ビット |
HPPA64 | HP PA-RISCアーキテクチャ、64ビット |
SH | SuperHアーキテクチャ、32ビット |
WebAssembly | WebAssembly仮想ISA (命令セットアーキテクチャ)、32ビット |
WASI | WebAssemblyシステムインターフェイス |
Alpha | Alphaアーキテクチャ |
Alpha_SoftFloat | AlphaソフトフロートABI |
Alpha_HardFloat | AlphaハードフロートABI |
LittleEndian | バイト順、最下位から |
BigEndian | バイト順、最上位から |
ELFv1 | 実行可能形式とリンク可能形式v1 |
ELFv2 | 実行可能およびリンク可能フォーマットv2 |
D_BetterC | ベターCコードとしてのD (コマンドラインスイッチ -betterC)が生成される |
D_Exceptions | 例外処理がサポートされている。 でコンパイルした場合、false に評価される。 コマンドラインスイッチ -betterC |
D_ModuleInfo | ModuleInfoがサポートされている。 コマンドラインスイッチでコンパイルする場合は、false に評価される。 に評価される。 -betterC |
D_TypeInfo | ランタイム型情報(TypeInfo )がサポートされている。 コマンドライン・スイッチでコンパイルする場合、false と評価される。 コマンド・ライン・スイッチ -betterC |
D_Coverage | コード・カバレッジ解析インスツルメンテーション (コマンドライン・スイッチ -cov)が生成される |
D_Ddoc | Ddocドキュメント (コマンドラインスイッチ -D)が生成されている |
D_InlineAsm_X86 | X86用インラインアセンブラが実装された |
D_InlineAsm_X86_64 | X86-64用インラインアセンブラが実装されている |
D_LP64 | Pointers 64ビットである (コマンドラインスイッチ -m64).(CのLP64モデルと混同しないこと)。 |
D_X32 | ポインタは32ビットだが、ワードは64ビットのままである(x32 ABI)(X86_64 と並行して定義可能)。 |
D_HardFloat | ターゲット・ハードウェアに浮動小数点ユニットがある |
D_SoftFloat | ターゲット・ハードウェアが浮動小数点ユニットを持たない |
D_PIC | 位置独立コード (コマンドラインスイッチ -fPIC)が生成されている |
D_PIE | 位置独立実行可能コード (コマンドラインスイッチ -fPIE)が生成される |
D_SIMD | ベクター拡張(__simd 経由)がサポートされている。 |
D_AVX | AVXベクタ命令がサポートされている |
D_AVX2 | AVX2ベクター命令がサポートされている |
D_Version2 | これはDバージョン2コンパイラである |
D_NoBoundsChecks | 配列境界チェックは無効である。 (コマンドラインスイッチ -boundscheck=off) |
D_ObjectiveC | ターゲットはObjective-Cとのインターフェイスをサポートしている。 |
D_ProfileGC | GC割り当てがプロファイリングされる (コマンドラインスイッチ -profile=gc) |
D_Optimized | 最適化を有効にしてコンパイルする (コマンドラインスイッチ -O) |
Core | 標準ランタイムのビルド時に定義される |
Std | 標準ライブラリのビルド時に定義される |
unittest | ユニットテストを有効にする (コマンドライン・スイッチ -unittest) |
assert | AssertExpressionsに対してチェックが行われる |
D_PreConditions | in契約に対してチェックが実行される |
D_PostConditions | out契約に対するチェックが発行される。 |
D_Invariants | クラス不変量と 構造体不変量のチェックが発行される。 |
none | コードの一部を無効にするために使用される。 |
all | 常に定義されている。none |
以下の識別子は定義されているが、非推奨である:
Version Identifier | Description |
---|---|
darwin | Darwinオペレーティング・システム。代わりにOSX 。 |
Thumb | 代わりにARM_Thumb を使用する。 |
S390X | System/390Xアーキテクチャ、64ビット;SystemZ を代わりに使う。 |
その他は、理にかなったものや新しい実装が現れたときに追加される。
この言語の将来的な成長を可能にするためである、 で始まるバージョン識別子の名前空間は、D_を示す識別子のために予約されている。 で始まるバージョン識別子名前空間は、D言語仕様または新機能への適合を示す識別子用に予約されている。 または新機能への適合性を示す識別子のために予約されている。さらに さらに、上記の識別子に任意の文字を付加して派生したすべての識別子が予約されている。これは ARM_foo Windows_bar は予約されていない。 foo_ARM やbar_Windows は予約されていない。
さらに、このリストにある定義済みのバージョン識別子は、コマンドラインやバージョン文から設定することはできない。 コマンドラインやバージョン文から設定することはできない。 (これにより、Windows とlinux が同時に設定されることを防ぐ)。
コンパイラー・ベンダー固有のバージョンは、商標登録されているベンダー識別子の前に のように、商標登録されたベンダー識別子が接頭辞として付いていれば、コンパイラー・ベンダー固有のバージョンを事前に定義することができる:
version(DigitalMars_funky_extension)
{
...
}
正しいバージョン識別子を正しい目的に使うことが重要である。 重要である。例えば、ベンダー固有の機能を使用する場合は、ベンダー識別子を使用する。 を使う。オペレーティング・システム固有の機能を使う場合は、オペレーティング・システム識別子を使う。 オペレーティング・システム固有の機能を使用する場合は、オペレーティング・システム識別子を使用する。
デバッグ条件
DebugCondition: debug debug ( Identifier )
一般的に、2つのバージョンのプログラムがビルドされる、 リリースビルドとデバッグビルドである。 デバッグビルドには、余分なエラーチェックコードが含まれる、 テスト・ハーネス、プリティ・プリンティング・コードなどが含まれる。 デバッグ文は条件付きでコンパイルされる。 ステートメント本体で条件付きでコンパイルする。 これは、C言語では / 。 #ifdef DEBUG /#endif のペアを使用する。
-debug スイッチがコンパイラに渡されると、debug の条件が満たされる。 コンパイラに渡される。
debug ( 識別子 ) の条件は、デバッグ識別子が識別子と一致したときに満たされる。 条件が満たされる。
class Foo { int a, b; debug: int flag; }
デバッグ・ステートメント
DebugConditionを持つConditionalStatementは、DebugStatementと呼ばれる。 と呼ばれる。DebugStatementsは、セマンティック・チェックが緩和されている。 pure @nogc 、nothrow 、@safe のチェックは行われない。 DebugStatementsは、pure,@nogc 、nothrow および@safe 属性の推論には影響しない。
デバッグ仕様
DebugSpecification: debug = Identifier ;
デバッグ識別子は、コマンド・ライン・スイッチ -debug またはDebugSpecificationによって設定される。
デバッグ指定は、それが現れるモジュールにのみ影響し、インポートされたモジュールには影響しない。 インポートされたモジュールには影響しない。インポートされたモジュールには影響しない。 独自の名前空間にあり、バージョン識別子や他の シンボルとは独立している。
デバッグ指定を前方参照することは違法である:
debug(foo) writeln("Foo"); debug = foo; // エラー、fooは設定前に使用されている
DebugSpecificationsはモジュール・スコープでのみ使用できる。
DebugSpecificationsはモジュール・スコープにのみ出現する。 のパラメータでビルドできる:
debug(identifier) { } // debugキーワードが識別子の場合、デバッグコードを追加する
これらはおそらく、コマンドラインから と-debug=識別子で設定されると思われる。
静的if条件
StaticIfCondition: static if ( AssignExpression )
AssignExpressionは暗黙的にboolean型に変換される、 コンパイル時に評価される。 この条件は、true と評価されれば満たされる。 false と評価された場合は満たされない。
AssignExpressionが暗黙的にブーリアン型に変換できない場合、またはコンパイル時に評価される場合はエラーとなる。 に暗黙的に変換できない場合、またはコンパイル時に評価できない場合はエラーとなる。
StaticIfConditions は、モジュール、クラス、テンプレート、構造体、共用体、関数のスコープで使用できる。 関数スコープでは、シンボルが参照される。 関数スコープでは、AssignExpressionで参照されるシンボルは、その時点で式が通常参照できるものであれば何でもよい。 で参照できるものであれば何でもよい。
const int i = 3; int j = 4; static if (i == 3) // モジュール・スコープでOK int x; class C { const int k = 5; static if (i == 3) // OK int x; else long x; static if (j == 3) // エラー、jは定数ではない int y; static if (k == 5) // OK、kは現在のスコープにある int z; }
template Int(int i) { static if (i == 32) alias Int = int; else static if (i == 16) alias Int = short; else static assert(0); // サポートされていない } Int!(32) a; // aはintである Int!(16) b; // bはshortである Int!(17) c; // エラー、static assertトリップ
StaticIfConditionは、以下の点でIfStatementと異なる。 Ifステートメントとは以下の点で異なる:
- 宣言文を条件付きでコンパイルするために使用できる、 ステートメントだけでなく、宣言の条件付きコンパイルにも使用できる。
- たとえ{ } が条件付きコンパイルされた文に使われたとしても、新しいスコープを導入することはない。
- 条件を満たさない場合、条件付きでコンパイルされたコードは構文的に正しくなければならない。 は構文的に正しくなければならない。意味的に正しい必要はない。 意味的に正しい必要はない。
- コンパイル時に評価可能でなければならない。
静的Foreach
StaticForeach: static AggregateForeach static RangeForeach StaticForeachDeclaration: StaticForeach DeclarationBlock StaticForeach : DeclDefsopt StaticForeachStatement: StaticForeach NoScopeNonEmptyStatement
集計/範囲境界はコンパイル時に評価され、次のようになる。 コンパイル時に評価され、コンパイル時エンティティのシーケンスに変換される。 コンパイル時にForeachStatement/ForeachRangeStatementで対応するコードを評価することで、一連のコンパイル時エンティティに変換される。 で対応するコードを評価する。そして、static foreach の本体が、コンパイル時にForeachStatement/ForeachRangeStatementに対応する回数だけコピーされる。 シーケンスの要素数に対応する回数コピーされる。 コピーされる。i回目のコピーでは、変数名がi番目のエントリにバインドされる。static foreach 変数名は、変数宣言(定数の場合)または変数宣言(定数の場合)として、シーケンスのi番目のエントリにバインドされる。enum 変数宣言(定数の場合)またはalias 宣言(シンボルの場合)として、変数の名前がシーケンスのi番目のエントリに束縛される。特にstatic foreach 変数は決して実行時変数ではない)。
static foreach(i; [0, 1, 2, 3]) { pragma(msg, i); }
static foreach 対応する 対応する 。(この場合 はタプルのコンパイル時シーケンスを生成し、その タプルはその後反復中にアンパックされる)。 foreach static foreach
static foreach(i, v; ['a', 'b', 'c', 'd']) { static assert(i + 'a' == v); }
ConditionalDeclarationsのボディと同様、ボディは新しいスコープを導入しない。static foreach ボディは新しいスコープを導入しない。したがって 宣言の生成に使用できる:
import std.range : iota; static foreach(i; iota(0, 3)) { mixin(`enum x`, i, ` = i;`); } pragma(msg, x0, " ", x1," ", x2); // 0 1 2
関数の内部で、展開のたびに新しいスコープを作りたい場合、 別の中括弧を使う:
void fun() { static foreach(s; ["hi", "hey", "hello"]) {{ enum len = s.length; // 各繰り返しに対してローカルである static assert(len <= 5); }} static assert(!is(typeof(len))); }
break とする。continue
static foreach はコード生成コンストラクトであり、ループではない。 ループではないので、break とcontinue を使って、その中の制御フローを変更することはできない。 を使うことはできない。適切な これは誤解を防ぐためである。 誤解を防ぐためである)。
int test(int x) { int r = -1; switch(x) { static foreach(i; 0 .. 100) { case i: r = i; break; // エラー } default: break; } return r; } static foreach(i; 0 .. 200) { static assert(test(i) == (i < 100 ? i : -1)); }
明示的なbreak/continue ラベルを使えば、この制限を回避できる。 この制限を避けることができる。(注釈:)static foreach 自体は、明示的にラベルを付けても、破ることも続けることもできない。 それ自体は、たとえ明示的にラベル付けされていても、壊すことも続けることもできないことに注意されたい)。 ラベルを付けても、 自体は壊すことも続けることもできないことに注意されたい)。
int test(int x) { int r = -1; Lswitch: switch(x) { static foreach(i; 0 .. 100) { case i: r = i; break Lswitch; } default: break; } return r; } static foreach(i; 0 .. 200) { static assert(test(i) == (i<100 ? i : -1)); }
static assert
StaticAssert: static assert ( ArgumentList ) ;
最初のAssignExpressionはコンパイル時に評価され、ブール値に変換される。 をブール値に変換する。その値が真であれば、"static assert" は無視される。 は無視される。値が偽の場合、エラー診断が発行され、コンパイルは失敗する。 が発行され、コンパイルは失敗する。
失敗した場合、後続のAssignExpressionsはそれぞれ文字列に変換され、連結される。 はそれぞれ文字列に変換され、連結される。結果の文字列は はエラー診断とともに出力される。
AssertExpressionsとは異なり、StaticAssertsは常にコンパイラによってチェックされ、評価される。 によってチェックされ、評価される。 を満たさない限り、コンパイラによって常にチェックされ、評価される。
void foo() { if (0) { assert(0); // 決してトリップしない static assert(0); // 常にトリップする } version (BAR) { } else { static assert(0); // バージョンBARが定義されていないときにトリップする } }
StaticAssertは、コードでサポートされていない条件構成に注意を促すのに便利なツールだ。 コードでサポートされていない
DEEPL APIにより翻訳、ところどころ修正。
このページの最新版(英語)
このページの原文(英語)
翻訳時のdmdのバージョン: 2.108.0
ドキュメントのdmdのバージョン: 2.109.1
翻訳日付 :
HTML生成日時:
編集者: dokutoku