我有一些代码最近被"移植"到VS。下面是生成的语句和汇编程序,希望"错误"是显而易见的。当然,它生成代码的方式可能是VS的一个特性,但我不能说我以前见过这种情况。
switchcount = (int) (*d++) + (*d++<<8) + (*d++<<16) + (*d++<<24);
00A722F6 mov eax,dword ptr [d]
00A722F9 movzx ecx,byte ptr [eax]
00A722FC mov edx,dword ptr [d]
00A722FF movzx eax,byte ptr [edx]
00A72302 shl eax,8
00A72305 add ecx,eax
00A72307 mov edx,dword ptr [d]
00A7230A movzx eax,byte ptr [edx]
00A7230D shl eax,10h
00A72310 add ecx,eax
00A72312 mov edx,dword ptr [d]
00A72315 movzx eax,byte ptr [edx]
00A72318 shl eax,18h
00A7231B add ecx,eax
00A7231D mov dword ptr ds:[0AD8CA8h],ecx
00A72323 mov ecx,dword ptr [d]
00A72326 add ecx,1
00A72329 mov dword ptr [d],ecx
所以编译器生成的代码本质上是
switchcount = (int) (*d) + (*d<<8) + (*d<<16) + (*d<<24);
d += 4 ;
有人能告诉我如何说服编译器生成正确的代码吗?
C不允许在序列点之间多次修改同一个变量,编译器可以随意处理它-就C标准而言,生成它所做的代码是完全可以的,但更有用的行为是中止编译,或者至少像clang那样发出警告:
warning: multiple unsequenced modifications to 'd' [-Wunsequenced]
编写代码的正确方法是
switchcount = (int) (d[0]) + (d[1]<<8) + (d[2]<<16) + (d[3]<<24);
d += 4;
附带说明一下,由于整数提升,int
的强制转换是不必要的,但如果您希望代码由C新手阅读,为了清晰起见,您可以将其保留下来。
根据d
的输入值,应将int
的强制转换替换为unsigned
的强制转换-否则,如果d[3]
至少为128,则最后一项将把值位移到符号位,这也是"未定义行为"(但如果整数由2的补码表示,则正常工作)。
在C中处理子表达式(如一条语句中的d++多次)的行为是未定义的。您现在面临着不同编译器对语句的不同解释方式——避免以这种方式使用表达式。
请参阅Pre&C、C++、Java和&C#