对于vc++,下面是关于前向声明和指定底层类型的测试:
下面的代码编译成功。
typedef int myint;
enum T ;
void foo(T * tp )
{
* tp = (T)0x12345678;
}
enum T : char
{
A
};
但是我得到了/W4的警告(/W3不招致这个警告)
使用非标准扩展名:为枚举“T”指定底层类型
vc++ (Microsoft (R) 32位C/ c++优化编译器版本15.00.30729.01 for 80x86)在上述情况下看起来有bug:
当看到枚举T时;VC假设枚举类型T使用默认的4字节int作为底层类型,因此生成的程序集代码为:
?foo@@YAXPAW4T@@@Z PROC ; foo
; File e:\work\c_cpp\cpp_snippet.cpp
; Line 13
push ebp
mov ebp, esp
; Line 14
mov eax, DWORD PTR _tp$[ebp]
mov DWORD PTR [eax], 305419896 ; 12345678H
; Line 15
pop ebp
ret 0
?foo@@YAXPAW4T@@@Z ENDP ; foo
上面的汇编代码是从/Fatest中提取的。这不是我个人的猜测。
你看到了吗
mov DWORD PTR[eax], 305419896 ; 12345678H
行吗?
下面的代码片段证明了这一点:
int main(int argc, char *argv)
{
union {
char ca[4];
T t;
}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] );
return 0;
}
结果是:
0x78, 0x56, 0x34, 0x12
删除枚举T的前向声明,并将函数foo的定义移动到枚举T的定义之后:结果为OK:
上面的键指令变成:
mov BYTE PTR [eax], 120;00000078 h
最终结果为:
0x78, 0x1, 0x1, 0x1
注意,该值没有被覆盖。
因此,在vc++中使用前向声明enum被认为是有害的。
顺便说一句,毫不奇怪,底层类型的声明语法与c#中的相同。在实践中,我发现在与内存有限的嵌入式系统通信时,通过将底层类型指定为char来节省三个字节是值得的。