VS2015编译疑问:movsx指令为何使用byte而非word?
首先我们先把你的代码和对应汇编清晰列出来:
C++ 代码:
int a = 2815; short c = static_cast<char>(a);
对应汇编:
00007FF78B5126EE mov dword ptr [a],0AFFh 00007FF78B5126F5 movsx ax,byte ptr [a] 00007FF78B5126FA mov word ptr [c],ax
要搞懂这个问题,得拆解你这条赋值语句的实际语义,以及编译器是怎么对应到汇编指令的:
第一步:理解static_cast<char>(a)的行为
你写的static_cast<char>(a)是把4字节的int类型a,强制转换为1字节的char类型(不管你的开发环境中int/short占多少字节,char通常都是1字节)。
这个转换的核心是截断高位:只保留a的最低1字节,抛弃剩下的3字节。你的a=2815对应的十六进制是0xAFF,所以它的最低1字节是0xFF,这就是static_cast<char>(a)的结果。
第二步:为什么用movsx ax, byte ptr [a]?
接下来要把这个1字节的char值,赋值给2字节的short类型c。因为short是有符号整数,所以需要把1字节的有符号值符号扩展到2字节(补全高位符号位),而movsx就是干这个的指令——它把源操作数(这里是1字节)的符号位填充到目标操作数(这里是16位的ax寄存器)的高位。
那为什么是byte ptr而不是word ptr?
- 如果用
word ptr,编译器会取a的低2字节(也就是0xAFF)来做符号扩展,但这完全不符合你写的static_cast<char>(a)的语义——你明确要求只取char长度的1字节,而不是short长度的2字节。 - 用
byte ptr才是精准对应了static_cast<char>的行为:只拿a的最低1字节,再扩展成short需要的2字节。
举个数值例子验证:static_cast<char>(0xAFF)得到的是0xFF(如果char是有符号的,这代表-1),经过movsx扩展到ax后就是0xFFFF(也就是short类型的-1),最终赋值给c的结果就是-1,这完全符合C++代码的预期。
如果你原本想的是把int直接截断成short(而不是先转char再转short),那代码应该写成short c = static_cast<short>(a);,这时候对应的汇编才会用word ptr相关的指令,但显然这和你现在的代码逻辑不同。
内容的提问来源于stack exchange,提问作者Shawn

