鉴于以下情况:
#include <stdint.h>
#include <stdio.h>
uint16_t foo(uint8_t* x)
{
uint16_t r = (x[1] << 8) | x[0];
return r;
}
uint16_t bar(uint8_t* x)
{
uint16_t r = ((uint16_t*) x)[0];
return r;
}
在 x86_64 上,GCC 和 Clang 都会生成类似于以下内容的代码:
foo: # @foo
.cfi_startproc
# BB#0: # %entry
movzbl (%rdi), %ecx
movzbl 1(%rdi), %eax
shll $8, %eax
orl %ecx, %eax
movzwl %ax, %eax
ret
bar: # @bar
.cfi_startproc
# BB#0: # %entry
movzwl (%rdi), %eax
ret
是否有任何原因导致 foo 没有优化为与 bar 等效(即执行单个 16 位加载)?负载对齐?
最佳答案
我不编写编译器,但我可以有很好的猜测:
编译器使用的标准优化技术都不会影响 foo
中的代码。要检测它是否与 bar
等效,需要进行特定的优化来发现此特定模式,并输出“改进的”代码。
那么,为什么没有对此进行具体的优化呢?可能是通常的原因:
"Insufficient return on investment"
换句话说,编码、调试和维护优化所花费的时间 - 以及检查此模式的每一行源代码所花费的额外编译时间 - 将淹没从中获得的任何好处。
当然,您已经有了 htons/ntohs
。我就用那些。
Alignment of loads?
这很有趣,我必须查一下。如果您的传入指针“x”未字对齐,则 bar
在许多架构上会崩溃,而 foo
应该仍然可以工作。
但是 x86 架构允许未对齐的负载,因此即使对于未对齐的 x 值,这两个函数也应该起作用。
关于c - gcc/clang 对 uint8_t* 数组中 uint16_t 的小端加载进行优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10839745/