VC++の場合、前方宣言と基になる型の指定に関するテストは次のとおりです。
- 次のコードは正常にコンパイルされます。
typedef int myint;
列挙型 T ;
void foo(T * tp )
{
* tp = (T)0x12345678;
}
列挙型 T : char
{
あ
};
しかし、/W4
(/W3
この警告は発生しません)の警告が表示されました
警告 C4480: 非標準の拡張機能が使用されています: 列挙型 'T' の基になる型を指定しています
- 上記の場合、VC++ (Microsoft (R) 32 ビット C/C++ 最適化コンパイラ バージョン 15.00.30729.01 for 80x86) はバグがあるように見えます。
- 列挙型 T を見たとき。VC は、列挙型 T が基になる型として既定の 4 バイトの int を使用することを前提としているため、生成されるアセンブリ コードは次のようになります。
?foo@@YAXPAW4T@@@Z PROC ; ふー
; ファイル e:\work\c_cpp\cpp_snippet.cpp
; 13行目
EBPをプッシュ
mov ebp、esp
; 14行目
mov eax, DWORD PTR _tp$[ebp]
mov DWORD PTR [eax], 305419896 ; 12345678H
; 15行目
ポップEBP
ret 0
?foo@@YAXPAW4T@@@Z ENDP ; ふー
上記のアセンブリ コードは、個人的な推測ではなく、/Fatest.asm から直接抽出したものです。
見えますか
mov DWORD PTR[eax], 305419896 ; 12345678H
ライン?
次のコード スニペットはそれを証明しています。
int main(int argc, char *argv)
{
組合{
char ca[4];
Tt;
}a;
a.ca[0] = a.ca[1] = a.[ca[2] = a.ca[3] = 1;
foo( &a.t) ;
printf("%#x, %#x, %#x, %#x\n", a.ca[0], a.ca[1], a.ca[2], a.ca[3] ) ;
0 を返します。
}
結果は次のとおりです。
0x78、0x56、0x34、0x12
- enum T の前方宣言を削除し、enum T の定義の後に関数 foo の定義を移動した後: 結果は OK です:
上記の重要な命令は次のようになります。
mov BYTE PTR [eax], 120 ; 00000078H
最終結果は次のとおりです。
0x78、0x1、0x1、0x1
値は上書きされないことに注意してください。
そのため、VC++ で enum の前方宣言を使用することは有害であると見なされます。
ところで、当然のことながら、基になる型の宣言の構文は C# と同じです。実際には、メモリが制限されている組み込みシステムと通信するときに、基になる型を char として指定することで 3 バイトを節約する価値があることがわかりました。