对于VC++,这里是关于前向声明和指定底层类型的测试:
- 以下代码可以编译通过。
typedef int myint;
enum T ;
void foo(T * tp )
{
* tp = (T)0x12345678;
}
enum T : char
{
A
};
但是我在使用/W4
(/W3
不会出现此警告)时得到了警告:
warning C4480: nonstandard extension used: specifying underlying type for enum 'T'
- 在上述情况下,VC++(Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86)看起来存在缺陷:
- 当看到enum 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.asm中提取,不是我个人的猜测。
你看到了吗?
mov DWORD PTR[eax], 305419896
这是什么意思?
下面的代码片段证明了它:
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的定义之后后,结果正确:
上述关键指令变为:
mov BYTE PTR [eax], 120; 00000078H
最终结果是:
0x78,0x1,0x1,0x1
请注意,值没有被覆盖。
因此,在VC++中使用枚举的前向声明被认为是有害的。
顺便提一下,为了不让你感到惊讶,声明基础类型的语法与 C# 中的语法相同。在实践中,我发现在与内嵌系统通信时,将基础类型指定为 char 可以节省三个字节,这对于内存有限的系统来说非常值得。