Microsoft C/C++ の拡張機能
更新 : 2007 年 11 月
ANSI C および ANSI C++ 規格に対する Visual C++ の拡張機能を以下に示します。
キーワード
Microsoft C++ の言語拡張機能では、いくつかの追加のキーワードを使用しています。完全な一覧については、『C++ Language Reference』の「C++ Keywords」を参照してください。先頭にアンダースコアが 2 つ付いているキーワードは、Microsoft の拡張機能です。
静的な定数型の整数 (または列挙) メンバのクラス外定義
標準 (/Za) では、データ メンバのクラス外定義が必要です。この例を次に示します。
class CMyClass {
static const int max = 5;
int m_array[max];
}
...
const int CMyClass::max; // out of class definition
/Ze では、静的で定数型の整数および列挙のデータ メンバのクラス外定義は省略可能です。クラス内に初期化子を持つことができるのは、静的で定数型の整数と列挙だけです。初期化式には、定数型の式を使用する必要があります。
クラス外定義を指定する場合は (クラス外定義がヘッダー ファイルに指定され、そのヘッダー ファイルを複数のソース ファイルでインクルードする場合)、エラーを防ぐために selectany を使用する必要があります。たとえば、次のようにします。
__declspec(selectany) const int CMyClass::max = 5;
キャスト
コンパイラは、次の 2 とおりの非 ANSI キャストをサポートします。
左辺値を生成するための非 ANSI キャスト
char *p; (( int * ) p )++;
この例を次のように書き換えると、ANSI C 規格に準拠します。
p = ( char * )(( int * )p + 1 );
関数ポインタからデータ ポインタへの非 ANSI キャスト
int ( * pfunc ) (); int *pdata; pdata = ( int * ) pfunc;
上の例と同じキャストを行い、ANSI 規格に準拠させるには、次に示すように関数ポインタをまず int 型にキャストし、その後データ ポインタにキャストします。
pdata = ( int * ) (int) pfunc;
可変長の引数リスト
コンパイラでは、可変個の引数を指定する関数宣言子を使用できます。その後ろには、型を指定する関数定義を記述します。
void myfunc( int x, ... );
void myfunc( int x, char * c )
{ }
単一行コメント
C コンパイラでは、次のように 2 つのスラッシュ (//) で始まる単一行コメントがサポートされています。
// This is a single-line comment.
スコープ
C コンパイラでは、次のようなスコープ関連のコードを記述できます。
extern を static として再定義する。
extern int clip(); static int clip() {}
同じスコープ内で typedef 定義を複数回記述する。
typedef int INT; typedef int INT;
関数宣言子をファイル スコープにする。
void func1() { extern int func2( double ); } int main( void ) { func2( 4 ); // /Ze passes 4 as type double } // /Za passes 4 as type int
非定数式で初期化したブロック スコープ変数を使用する。
int clip( int ); int bar( int ); int main( void ) { int array[2] = { clip( 2 ), bar( 4 ) }; } int clip( int x ) { return x; } int bar( int x ) { return x; }
データの宣言と定義
C コンパイラでは、以下のデータ宣言およびデータの機能をサポートしています。
初期化子内に文字定数と文字列定数を混在させる。
char arr[5] = {'a', 'b', "cde"};
ビット フィールドを unsigned int や signed int 以外のベース型で指定する。
ストレージ クラスもデータ型も指定せずに宣言子を使用する。
x; int main( void ) { x = 1; }
可変長配列を構造体および共用体の最後のフィールドとして指定する。
struct zero { char *c; int zarray[]; };
名前のない (無名) 構造体を使用する。
struct { int i; char *s; };
名前のない (無名) 共用体を使用する。
union { int i; float fl; };
名前のないメンバを使用する。
struct s { unsigned int flag : 1; unsigned int : 31; }
浮動小数点組み込み型の関数
コンパイラは、/Oi が指定されている場合に、x86 固有の仕様→atan、atan2、cos、exp、log、log10、sin、sqrt、および tan の各関数の← x86 固有の仕様インライン生成をサポートします。これらの関数のインライン形式では errno 変数が設定されないため、C プログラムでは ANSI C に準拠しなくなります。
const ポインタ パラメータの参照を予測している関数に非 const ポインタ パラメータを渡す
これは C++ の拡張機能です。次のコードを /Ze でコンパイルします。
typedef int T;
const T acT = 9; // A constant of type 'T'
const T* pcT = &acT; // A pointer to a constant of type 'T'
void func2 ( const T*& rpcT ) // A reference to a pointer to a constant of type 'T'
{
rpcT = pcT;
}
T* pT; // A pointer to a 'T'
void func ()
{
func2 ( pT ); // Should be an error, but isn't detected
*pT = 7; // Invalidly overwrites the constant 'acT'
}
ISO646.H が有効でない
/Ze で次の演算子の表示形式を使用する場合は、iso646.h をインクルードする必要があります。
&& (and)
&= (and_eq)
& (bitand)
| (bitor)
~ (compl)
! (not)
!= (not_eq)
|| (or)
|= (or_eq)
^ (xor)
^= (xor_eq)
リテラル文字列のアドレスの型が const char (*) [] ではなく const char [] である
/Za で char const (*)[4] を出力し、/Ze で char const [4] を出力する例を次に示します。
#include <stdio.h>
#include <typeinfo>
int main()
{
printf_s("%s\n", typeid(&"abc").name());
}