我有一些最近被“移植”到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 ;
有人能告诉我如何说服编译器生成正确的代码吗?
答案 0 :(得分:3)
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,你的最后一个术语会将值位移到符号位,这又是“未定义的行为”。 (但如果整数由两个补码表示,通常按预期工作。)
答案 1 :(得分:0)
在一个语句中用于处理子表达式的行为(如d ++ mutliple次)是未定义的。您现在面临着不同编译器对语句的不同解释方式 - 避免以这种方式使用表达式。
请参阅Pre & post increment operator behavior in C, C++, Java, & C#