为什么在将C向下转换从unsignedint转换为unsignedchar时,movl比movb更受欢迎?

考虑向下转换unsigned为的精简示例unsigned char

void unsigned_to_unsigned_char(unsigned *sp, unsigned char *dp)
{
  *dp = (unsigned char)*sp;
}

上面的 C 代码被翻译成汇编代码,gcc -Og -S如下所示

movl    (%rdi), %eax
movb    %al, (%rsi)

出于什么原因,C 到汇编的翻译不是如下所示?

movb    (%rdi), %al
movb    %al, (%rsi)

是因为这是不正确的,还是因为比movl它更传统或更短的编码movb

回答

当新的低字节与相应 32/64 位寄存器的旧高字节合并时,写入 8 位 x86 寄存器可能会导致额外的合并微操作。这也可能导致对寄存器先前值的意外数据依赖性。

出于这个原因,通常只写入 x86 上通用寄存器的 32/64 位变体通常是个好主意。


回答

您问题中的强制转换是完全没有必要的,因为无论如何该语言都会在赋值之前有效地执行该强制转换,因此它对生成的代码没有任何贡献(删除它并且看不到任何更改,没有错误或警告)。

右手边的尊重是unsigned int这样的,这就是它所做的。给定 32 位总线,执行字取消引用(模对齐问题)不会降低性能。

如果你想要其他,你可以在取消引用之前进行转换,如下所示:

void unsigned_to_unsigned_char(unsigned *sp, unsigned char *dp)
{
  *dp = *(unsigned char *)sp;
}

这将产生您期望的字节移动指令。

https://godbolt.org/z/57nzrsrMe

  • @aafulei:规则并不复杂:它们几乎等于“避免编写部分寄存器”[为什么 GCC 不使用部分寄存器?](/sf/ask/2910145171/),除了当优化大小优先时。

以上是为什么在将C向下转换从unsignedint转换为unsignedchar时,movl比movb更受欢迎?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>