You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何MOVZX r64,r/m8表现同MOVZX r32,r/m8?MOVSX表现符合预期

无符号/有符号扩展指令差异的原因分析

测试代码与现象

无符号赋值的C代码:

int main()
{
     unsigned long int ui64{};
     unsigned char ui8{ 0xAA };
     unsigned short ui16 { 0xBBBB};
     ui64 = ui8;
     ui64 = ui16;
}

生成的汇编使用0F B6 /r MOVZX r32, r/m8和0F B7 /r MOVZX r32, r/m16,而非64位版本的REX.W + 0F B6 /r MOVZX r64, r/m8、REX.W + 0F B7 /r MOVZX r64, r/m16。

有符号赋值的C代码:

int main()
{
    long int i64{};
    char i8{ 1 };
    short i16 {2};

    i64 = i8;
    i64 = i16;
}

生成的汇编则使用预期的64位符号扩展指令REX.W + 0F BE /r MOVSX r64, r/m8和REX.W + 0F BF /r MOVSX r64, r/m16。

核心原因

这种差异源于x86-64架构的寄存器行为特性,以及无符号、有符号扩展的本质区别:

  1. 无符号扩展(MOVZX)的场景
    x86-64架构规定:当对32位通用寄存器(如EAX、EBX)执行写入操作时,对应的64位寄存器(如RAX、RBX)的高32位会被自动清零。
    对于无符号类型的赋值,将unsigned char/unsigned short零扩展到32位后,再写入64位寄存器,最终的64位值和直接零扩展到64位的结果完全一致(因为无符号值的高32位本身就是0)。
    同时,32位版本的MOVZX指令(3字节)比64位版本(4字节)更短,能减少指令长度、提升指令缓存利用率,因此编译器会选择更高效的32位MOVZX指令。

  2. 有符号扩展(MOVSX)的场景
    有符号扩展的核心是要保持数值的符号位一致性:如果原始值是负数,扩展后的高比特位必须全部为1。
    如果先将char/short符号扩展到32位,再写入64位寄存器,x86-64的自动清零高32位特性会破坏符号扩展的结果——比如负数的32位扩展值是0xFFFFFFFF,写入64位寄存器后会变成0x00000000FFFFFFFF,这显然不是正确的64位有符号值(正确应为0xFFFFFFFFFFFFFFFF)。
    因此编译器必须直接使用64位版本的MOVSX指令,一次性将8/16位有符号值符号扩展到64位,保证结果的正确性。

内容的提问来源于stack exchange,提问作者rand_program

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 03:23:30