我有一个应用程序,它使用一个数据库,其中的数据以大端顺序存储。为了跨硬件平台可移植地访问此数据,我使用了config.h模块中定义的4个宏:
word(p) - gets a big-endian 16 bit value at pointer p as a native 16-bit value.
putword(p, w) - stores a native 16-bit variable (w) to pointer p as 16-bit big-endian.
dword(p) and putdword(p, d) do the same for 32-bit values
这一切都运行得很好,但是小端机器上的宏使用暴力的“移位和掩码”方法。
无论如何,看起来在linux上有builtin_bswap16和builtin_bswap32函数可以更有效地完成这项工作(作为内联汇编代码?)。那么,怎样才是编写word/putword宏的正确方法,以便它们在X86_64 linux机器上使用这些内置函数呢?将我的宏编码为htons/l函数调用是否可以有效地完成相同的事情--是否需要启用编译器优化才能使这些解决方案中的任何一个工作?如果它使gdb变得无用,我宁愿不要优化。
发布于 2021-04-05 06:15:47
嗯。我写了一个简单的测试程序,不使用特殊的包含文件,只需调用__builtin_swap...直接执行函数(请参阅“快速...”下面的宏)。一切都很好用。当我在gdb中反汇编代码时,我发现快速...宏在4-5条汇编指令中执行,对于最坏情况下的'dword‘宏,需要多达27条指令。相当整洁的改进,几乎不需要付出任何努力。
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
#define word(a) (ushort) ( (*((uchar *)(a)) << 8) | \
(*((uchar *)(a) + 1)) )
#define putword(a,w) *((char *)(a)) = (char) (((ushort)((w) >> 8)) & 0x00ff), \
*((char *)(a)+1) = (char) (((ushort)((w) >> 0)) & 0x00ff)
#define dword(a) (uint) ( ((uint)(word(a)) << 16) | \
((uint)(word(((uchar *)(a) + 2)))) )
#define putdword(a,d) *((char *)(a)) = (char) (((uint)((d) >> 24)) & 0x00ff), \
*((char *)(a)+1) = (char) (((uint)((d) >> 16)) & 0x00ff), \
*((char *)(a)+2) = (char) (((uint)((d) >> 8)) & 0x00ff), \
*((char *)(a)+3) = (char) (((uint)((d) >> 0)) & 0x00ff)
#define fastword(a) (ushort) __builtin_bswap16(* ((ushort *) a));
#define fastputword(a, w) *((ushort *) a) = __builtin_bswap16((ushort)w);
#define fastdword(a) (uint) __builtin_bswap32(* ((uint *) a));
#define fastputdword(a, d) *((uint *) a) = __builtin_bswap32((uint)d);
int main()
{
unsigned short s1, s2, s3;
unsigned int i1, i2, i3;
s1 = 0x1234;
putword(&s2, s1);
s3 = word(&s2);
i1 = 0x12345678;
putdword(&i2, i1);
i3 = dword(&i2);
printf("s1=%x, s2=%x, s3=%x, i1=%x, i2=%x, i3=%x\n", s1, s2, s3, i1, i2, i3);
s1 = 0x1234;
fastputword(&s2, s1);
s3 = fastword(&s2);
i1 = 0x12345678;
fastputdword(&i2, i1);
i3 = fastdword(&i2);
printf("s1=%x, s2=%x, s3=%x, i1=%x, i2=%x, i3=%x\n", s1, s2, s3, i1, i2, i3);
}
发布于 2021-04-05 07:56:00
我只会使用htons, htonl
和朋友。它们的可移植性要好得多,任何给定libc的作者很可能已经将它们实现为调用__builtin
内部函数或内联asm或其他任何东西的内联函数或宏,从而为特定机器实现了一个近乎最佳的实现。See what is generated in godbolt's setup,我认为这是Linux/glibc的一种风格。
您确实需要使用优化进行编译才能将它们内联,否则它会生成一个普通的函数调用。但即使是-Og
也会将它们内联起来,不会把调试搞得一团糟。无论如何,如果您在编译时完全没有进行优化,那么整个程序的效率将非常低,因此调用htons
的额外指令肯定是您最不担心的。
https://stackoverflow.com/questions/66935920
复制相似问题