C++ 中的 64 位整数是否有任何“标准”类似 htonl 的函数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3022552/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 11:50:16  来源:igfitidea点击:

Is there any "standard" htonl-like function for 64 bits integers in C++?

c++64-bitportabilityendiannesshtonl

提问by ereOn

I'm working on an implementation of the memcache protocol which, at some points, uses 64 bits integer values. These values must be stored in "network byte order".

我正在研究 memcache 协议的实现,该协议在某些时候使用 64 位整数值。这些值必须以“网络字节顺序”存储。

I wish there was some uint64_t htonll(uint64_t value)function to do the change, but unfortunately, if it exist, I couldn't find it.

我希望有一些uint64_t htonll(uint64_t value)功能可以进行更改,但不幸的是,如果它存在,我找不到它。

So I have 1 or 2 questions:

所以我有1或2个问题:

  • Is there any portable(Windows, Linux, AIX) standard function to do this ?
  • If there is no such function, how would you implement it ?
  • 是否有任何可移植的(Windows、Linux、AIX)标准功能可以做到这一点?
  • 如果没有这样的功能,你将如何实现它?

I have in mind a basic implementation but I don't know how to check the endianness at compile-time to make the code portable. So your help is more than welcome here ;)

我想到了一个基本的实现,但我不知道如何在编译时检查字节序以使代码可移植。所以在这里非常欢迎您的帮助;)

Thank you.

谢谢你。



Here is the final solution I wrote, thanks to Brian's solution.

这是我写的最终解决方案,感谢布赖恩的解决方案。

uint64_t htonll(uint64_t value)
{
    // The answer is 42
    static const int num = 42;

    // Check the endianness
    if (*reinterpret_cast<const char*>(&num) == num)
    {
        const uint32_t high_part = htonl(static_cast<uint32_t>(value >> 32));
        const uint32_t low_part = htonl(static_cast<uint32_t>(value & 0xFFFFFFFFLL));

        return (static_cast<uint64_t>(low_part) << 32) | high_part;
    } else
    {
        return value;
    }
}

采纳答案by Brian R. Bondy

You are probably looking for bswap_64I think it is supported pretty much everywhere but I wouldn't call it standard.

您可能正在寻找bswap_64我认为它几乎在任何地方都得到支持,但我不会称其为标准。

You can easily check the endianness by creating an int with a value of 1, casting your int's address as a char*and checking the value of the first byte.

您可以通过创建一个值为 1 的 int,将您的 int 的地址转换为 achar*并检查第一个字节的值来轻松检查字节序。

For example:

例如:

int num = 42;
if(*(char *)&num == 42)
{
   //Little Endian
}
else
{
   //Big Endian
} 

Knowing this you could also make a simple function that does the swapping.

知道了这一点,您还可以制作一个简单的函数来进行交换。



You could also always use boost which contains endian macros which are portable cross platform.

您也可以始终使用包含可移植跨平台的字节序宏的 boost。

回答by deltamind106

#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
#define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))

The test (1==htonl(1)) simply determines (at runtime sadly) if the hardware architecture requires byte swapping. There aren't any portable ways to determine at compile-time what the architecture is, so we resort to using "htonl", which is as portable as it gets in this situation. If byte-swapping is required, then we swap 32 bits at a time using htonl (remembering to swap the two 32 bit words as well).

测试 (1==htonl(1)) 只是确定(遗憾的是在运行时)硬件架构是否需要字节交换。没有任何可移植的方法可以在编译时确定架构是什么,因此我们求助于使用“htonl”,它在这种情况下具有可移植性。如果需要字节交换,那么我们使用 htonl 一次交换 32 位(记住也要交换两个 32 位字)。



Here's another way to perform the swap that is portable across most compilers and operating systems, including AIX, BSDs, Linux, and Solaris.

这是在大多数编译器和操作系统(包括 AIX、BSD、Linux 和 Solaris)中可移植的执行交换的另一种方法。

#if __BIG_ENDIAN__
# define htonll(x) (x)
# define ntohll(x) (x)
#else
# define htonll(x) ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
# define ntohll(x) ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
#endif

The important part is to use __BIG_ENDIAN__or __LITTLE_ENDIAN__; and not __BYTE_ORDER__, __ORDER_BIG_ENDIAN__or __ORDER_LITTLE_ENDIAN__. Some compilers and operating systems lack __BYTE_ORDER__and friends.

重要的部分是使用__BIG_ENDIAN____LITTLE_ENDIAN__;而不是__BYTE_ORDER____ORDER_BIG_ENDIAN____ORDER_LITTLE_ENDIAN__。一些编译器和操作系统缺乏__BYTE_ORDER__和朋友。

回答by suresh m

You can try with uint64_t htobe64(uint64_t host_64bits)& uint64_t be64toh(uint64_t big_endian_64bits)for vice-versa.

您可以尝试使用uint64_t htobe64(uint64_t host_64bits)& uint64_t be64toh(uint64_t big_endian_64bits)反之亦然。

回答by pix0r

This seems to work in C; did I do anything wrong?

这似乎适用于 C;我做错了什么吗?

uint64_t htonll(uint64_t value) {
    int num = 42;
    if (*(char *)&num == 42) {
        uint32_t high_part = htonl((uint32_t)(value >> 32));
        uint32_t low_part = htonl((uint32_t)(value & 0xFFFFFFFFLL));
        return (((uint64_t)low_part) << 32) | high_part;
    } else {
        return value;
    }
}

回答by user3734255

To reduce the overhead of the "if num == ..." Use the pre-processor defines:

要减少“if num == ...”的开销,请使用预处理器定义:

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#else
#endif

回答by FuriousSlowpoke

Well, I think it's better to use the endian switching at compile time as much as possible, but I prefer to use function instead of macro, because in a macro the parameters are just replaced by the arguments; so arguments can be evaluated multiple times and create weird result if they are present multiple times in the macro (as done in some of the previous provided solutions).

好吧,我认为在编译时尽可能使用字节序切换会更好,但我更喜欢使用函数而不是宏,因为在宏中参数只是被参数替换;因此,如果参数在宏中多次出现,则可以多次评估参数并产生奇怪的结果(如之前提供的一些解决方案中所做的那样)。

uint64_t htonll(uint64_t x)
{
#if __BIG_ENDIAN__
    return x;
#else
    return ((uint64_t)htonl((x) & 0xFFFFFFFFLL) << 32) | htonl((x) >> 32);
#endif
}

uint64_t ntohll(uint64_t x)
{
#if __BIG_ENDIAN__
    return x;
#else
    return ((uint64_t)ntohl((x) & 0xFFFFFFFFLL) << 32) | ntohl((x) >> 32);
#endif
}

So this allow calling htonll(x++) without increment x several time like it will be done using the previous macros.

所以这允许调用 htonll(x++) 而不增加 x 几次,就像使用以前的宏一样。

回答by Pavel Radzivilovsky

EDIT: combining the two (used Brian's code):

编辑:结合两者(使用布赖恩的代码):

uint64_t htonll(uint64_t value)
{
     int num = 42;
     if(*(char *)&num == 42)
          return (htonl(value & 0xFFFFFFFF) << 32LL) | htonl(value >> 32);
     else 
          return value;
}

Warning: untested code! Please test before using.

警告:未经测试的代码!使用前请先测试。