Clang 拡張 C++ コンパイラと旧世代の C++ コンパイラの違い
Clang 拡張 C++ コンパイラ への移動
このトピックでは、Clang 拡張 C++ コンパイラとその直接の前身である BCC32 の違いを概観します。
目次
- 1 コマンドライン オプション
- 2 より厳密な C++ コンパイラ
- 3 警告とエラー メッセージ
- 4 定義済みマクロ
- 5 #include パスとルックアップ
- 6 プリコンパイル済みヘッダー
- 7 オブジェクト ファイルとライブラリ ファイルの形式
- 8 __property:複合代入および連鎖代入
- 9 非推奨の BCC32 拡張キーワードおよびキーワード
- 10 サポートされていない BCC32 の属性
- 11 Unicode 識別子はサポートされていない
- 12 インライン アセンブリ
- 13 try ブロックで処理できない一部の例外
- 14 Office XP オートメーション ユニットがサポートされない
- 15 関連項目
コマンドライン オプション
Clang 拡張 C++ コンパイラでは、ほぼ完全に異なる コマンドライン オプション セットを使用し、同じオプションの複数の値を表現するのに別の手段を用います。
より厳密な C++ コンパイラ
Clang 拡張 C++ コンパイラは BCC32 より厳密に C++ 言語標準に準拠しています。 C++11 をサポートしていますが、その扱いもより厳密です。 「より厳密な C++ コンパイラ(Clang 拡張 C++ コンパイラ)」を参照してください。
警告とエラー メッセージ
より具体的かつ詳細な新しい警告およびエラー メッセージに加えて、Clang 拡張 C++ コンパイラでは、BCC32 で検出された状況についてのメッセージを異なる言いまわしで表現しています。
詳細は、「Clang 拡張 C++ コンパイラのエラーと警告」を参照してください。
定義済みマクロ
Clang 拡張 C++ コンパイラを使用すると、すべての定義済みマクロをプリプロセッサから直接取得することができます。
RTLVersion マクロ
RTLVersion 定数は Clang 拡張 C++ コンパイラではサポートされていません。 代わりに、RTLVersionC を使用できます。
NO_STRICT マクロ
NO_STRICT の型チェック方式は Clang 拡張 C++ コンパイラではサポートされていません。 NO_STRICT 条件定義を使用している既存のプロジェクトがある場合は、NO_STRICT を削除しなければなりません。
NO_STRICT 条件定義を削除する詳細手順は、「C++ アプリケーションでの厳密な型チェックの使用」を参照してください。
#include
パスとルックアップ
Clang 拡張コンパイラでは、#include
ヘッダー のインクルード方法が異なる場合があります。
たとえば、Clang 拡張 C++ コンパイラでは、BCC32 とは異なり、半絶対パスで指定されたヘッダーは検索されません。 'myOtherFile' が C:/myProjectsDir/myOtherApp にあるとすると、.CPP ファイルで以下のように参照するのは、Clang 拡張 C++ コンパイラでも BCC32 でも問題ありません。
#include "c:/myProjectsDir/myApp/mySource.h" // Absolute path.
#include "../myApp/mySource.h" // Relative path.
しかし、以下のように参照すると、BCC32 では問題ありませんが、Clang 拡張 C++ コンパイラではエラーが発生します。
#include "/myProjectsDir/myApp/mySource.h" // Semi-absolute path.
Clang 拡張 C++ コンパイラでは以下のエラーが出力されます。
[<compiler> Fatal Error] myOtherFile.cpp(27): '/myProject/myApp/mySource.h' file not found
詳細については、「Clang 拡張 C++ コンパイラ、#include パスとルックアップ」を参照してください。
プリコンパイル済みヘッダー
BCC32 と比べて、Clang 拡張 C++ コンパイラでは、プリコンパイル済みヘッダーの働きが少し異なります。 各 C++ プロジェクトにはプリコンパイル済みヘッダーが 1 つだけ存在でき、新規 C++ プロジェクトごとに( projectPCHn.h という名前の)デフォルトのプリコンパイル済みヘッダーが生成されます。
詳細は、以下のトピックを参照してください。
オブジェクト ファイルとライブラリ ファイルの形式
- BCC32 とその関連ツールでは、
.obj
ファイルと.lib
ファイルで OMF を使用します。 - Clang 拡張 C++ コンパイラでは、
.o
ファイルと.a
ファイルで ELF を使用します。
この違いは、たとえば、32 ビット Windows アプリケーションを移行するときは、.lib
ファイルと .obj
ファイルへの参照をそれぞれ .a
と .o
に変更する必要がある、ということです。
__property:複合代入および連鎖代入
Clang 拡張 C++ コンパイラでは __property
の複合代入をサポートしていますが、BCC32 ではサポートしていません。
キーワード __property
の対象はフィールドやメンバとは異なります。これらは単純代入で使用しなければなりません。
BCC32 でも RAD Studio の Clang 拡張 C++ コンパイラでも __property
を以下のように複合代入で使用することはできますが、
Form1->Caption += DateToStr(Now());
BCC32 では、設定アクセサではなく取得アクセサを呼び出すだけです。そのため、複数のプラットフォームをターゲットにする場合は、このような構文を使用しないことをお勧めします。
これらのコンパイラでは、以下のように連鎖代入で __property を使用することはできません。
Button2->Caption = Button1->Caption = DateToStr(Now()); // Error
非推奨の BCC32 拡張キーワードおよびキーワード
コンパイラの拡張キーワードのうち、アンダースコアの付かないものやアンダースコアが 1 つだけ付くものは、Clang 拡張 C++ コンパイラではサポートされていないか推奨されていません。 二重のアンダースコアが付くバージョンを使用してください(それらは BCC32 でもサポートされています)。
cdecl
、_cdecl
:__cdecl
を使用pascal
、_pascal
:__pascal
を使用_fastcall
:__fastcall
を使用(現在は、Borland 形式ではなく Microsoft 形式になっています)_stdcall
:__stdcall
を使用_fortran
、__fortran
: サポートされていない(廃止)asm
、_asm
、__asm
: インライン アセンブリはサポートされていない_export
:__export
を使用_import
:__import
を使用_declspec
:__declspec
を使用
サポートされていない BCC32 の属性
「Workaround for C++11 属性の回避策(Clang 拡張 C++ コンパイラ)」(noreturn と final)を参照してください。
Unicode 識別子はサポートされていない
Unicode は、リテラル文字列とファイル名では使用できますが、識別子では使用できません。
インライン アセンブリ
Clang 拡張 C++ コンパイラではインライン アセンブリを使用できますが、次の点に注意が必要です。
- アセンブリ コードと C++ コードを混在させることはできません。
- スタック ポインタ(RSP)を使用してはいけません。
- アセンブラでは、よりなじみのあるブロック単位の Intel 形式ではなく、行単位の AT&T 形式を使用する必要があります。詳細は、「GCC インライン アセンブリの使用法」(英語版)を参照してください。
Clang 拡張 C++ コンパイラでは、以下のように、BCC32 でサポートされているインライン アセンブリとは異なる形式でインライン アセンブリをサポートしています。
- 異なるアセンブリ構文:
- Clang 拡張 C++ コンパイラでサポートされているアセンブリ構文は、よりなじみのあるブロック単位の Intel 形式ではなく、行単位の AT&T 形式です。
- 例外処理やデバッグで発生するおそれのある問題:
- 手動で作成したアセンブリ コードと C++ コードが混在する場合、コンパイラの例外処理で負荷がさらに増えます。(NASM や MASM などの別個のアセンブラを使って)すべてアセンブリで記述された関数をプログラムにリンクすることができます。ただし、あらかじめ知っておかなければならない特有の問題(例外処理やデバッグで発生するおそれのある問題)があります。
- インライン アセンブリについてのこれらの問題の理由は、ひと言で言えば pdata です。インライン アセンブリがサポートされないケースは少なくありません。例外(およびデバッグ)が正しく機能するには、各関数と例外が送出された場合に巻き戻す必要がある情報を記述したデータ構造体(pdata)がコードで生成されなければなりません。インライン アセンブリをいったん挿入したら、コンパイラは詳細情報(インライン アセンブリによって割り当てられた追加のスタック領域など)を把握できません。インライン アセンブリ(つまり、アセンブリと C/C++ が混在したコード)があると、コンパイラが pdata 構造体を正確に生成できなくなります。pdata の詳細は、http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx を参照してください。
Clang 拡張 C++ コンパイラでのインライン アセンブリの使用方法を説明するコード例は、「BCC64 のインライン アセンブリ(C++)」を参照してください。
Clang 拡張 C++ コンパイラでのアセンブリの詳細は、以下を参照してください。
- http://clang.llvm.org/compatibility.html#inline-asm
- http://www.codeproject.com/Articles/15971/Using-Inline-Assembly-in-C-C
- http://wiki.osdev.org/Inline_Assembly/Examples
try ブロックで処理できない一部の例外
同期例外は、プログラムまたはプログラムで使用されるライブラリで throw 文の使用により発生する例外です。これらの例外がいつどこで発生するかは、コンパイル時にわかります。
一方、非同期例外は、オペレーティング システムを発生源とする、いつでも発生する可能性のある例外です(たとえば、ゼロ除算やアクセス違反など)。
標準の C および C++ は、同期例外のみ処理するように設計されています。ただし、C++Builder アプリケーションが RTL にリンクされると、アプリケーションで非同期例外も捕捉できるようになります。
しかし、Clang は同期例外にのみ対応しており、非呼び出し例外の処理をサポートしていません。 try ブロックに、throw 文も throw 文が含まれている可能性のある関数の呼び出しも含まれていない場合、Clang では、その try ブロックに付随する catch ブロックや __finally (C++) ブロックをすべて無視します。 つまり、try ブロックで同期例外を送出できない場合、その try ブロックでは非同期例外を捕捉することもできません。
次に例を示します。
float a = 1;
float b = 0;
try {
try {
a = a / b; // The RTL throws an asynchronous exception (division by zero).
}
__finally {
// Execution never reaches this point.
}
}
catch (...) {
// Execution never reaches this point.
}
Clang ベースのコンパイラで処理できないこれらの特殊な例外については、それらを捕捉するのではなく、次のいずれかを行う必要があります。
- 非同期例外が発生する可能性のあるコードを、それ専用の関数に移動し、その関数を try ブロックから呼び出す。
- これらの例外が決して発生しないように努める。たとえば、上記の例では、除算を実行する前に
b
の値をチェックすることができるでしょう。
- メモ: 非同期例外を処理しない場合は、アプリケーションの GUI フレームワークのデフォルト例外ハンドラでそれらが捕捉され、アプリケーションから外部例外 EEFFACE が発生します。
Office XP オートメーション ユニットがサポートされない
Office 2010 オートメーション ユニットへのアップグレードで、XP 機能その他を使用することができるようになります。