生产问题导致我们的团队遇到以下问题:
ntohs
和ntohl
?我知道问题背后的含义可能看起来有些牵强和荒谬,但我被要求调查。
有问题的硬件是英特尔盒子,小端,64位处理器,并以64位编译。
答案 0 :(得分:12)
执行以下操作:
#include <arpa/inet.h>
int main()
{
volatile uint32_t x = 0x12345678;
x = ntohl(x);
return 0;
}
然后编译:
$ gcc -O3 -g -save-temps test.c
分析生成的test.s
文件,或者运行objdump -S test.o
。
在我的机器(Ubuntu 13.4)中,相关的asssembler是:
movl $305419896, 12(%esp)
movl 12(%esp), %eax
bswap %eax
movl %eax, 12(%esp)
提示:
12(%esp)
是volatile变量的地址。movl
说明适用于volatile
- x
的{{1}}。唯一真正有趣的指令是bswap
。ntohl
被编译为内联内在。此外,如果我查看test.i
(预编译输出),我会发现ntohl
#defined
只是__bswap_32()
,它只是一个内联函数致电__builtin_bswap32()
。
答案 1 :(得分:11)
/usr/include/bits/byteswap.h
中查找__bswap_16
和__bswap_32
函数,这些函数在启用优化时使用(请参阅<netinet/in.h>
详情如何。)-save-temps
选项保留中间.s
文件,或使用-S
在编译后和汇编代码之前停止,或使用http://gcc.godbolt.org/ 答案 2 :(得分:7)
这些是在glibc中实现的。看看/usr/include/netinet/in.h。他们很可能依赖于glibc byteswap宏(我机器上的/usr/include/bits/byteswap.h)
这些是在我的标题中的汇编中实现的,所以应该非常快。对于常量,这是在编译时完成的。
答案 3 :(得分:1)
GCC / glibc导致ntohl()和htonl()被内联到调用代码中。因此,避免了函数调用开销。此外,每个ntohl()或htonl()调用都被转换为单个bswap汇编程序操作。根据“英特尔®64和IA-32架构优化参考手册”,bswap在所有当前的英特尔CPU上都具有“1”的延迟和吞吐量。因此,执行ntohl()或htonl()只需要一个CPU时钟。
ntohs()和htons()被实现为8位旋转。这有效地交换了16位操作数的两半。延迟和吞吐量与bswap类似。