首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C++中的64位ntohl()?

C++中的64位ntohl()?
EN

Stack Overflow用户
提问于 2009-05-01 01:53:08
回答 16查看 89.7K关注 0票数 67

htonl()的手册页似乎建议您只能将其用于最多32位的值。(实际上,ntohl()是为unsigned long定义的,在我的平台上是32位的。我猜想如果无符号的长整型是8字节,它将适用于64位整数)。

我的问题是,我需要将64位整数(在我的例子中,这是一个无符号的long long)从大端转换为小端。现在,我需要进行特定的转换。但是,如果目标平台是高字节优先的,函数(如ntohl())不能转换我的64位值,那就更好了。(我宁愿避免添加我自己的预处理器魔法来做这件事)。

我能用什么?我想要一些标准的东西,如果它存在的话,但我对实现建议持开放态度。我在过去见过使用联合进行这种类型的转换。我想我可以有一个unsigned long long和一个char8的联合。然后相应地交换字节。(显然会在高字节优先的平台上崩溃)。

EN

回答 16

Stack Overflow用户

发布于 2010-12-11 00:02:29

文档: Linux上的man htobe64 (glibc >= 2.9)或FreeBSD。

不幸的是,在2009年的一次尝试中,OpenBSD、FreeBSD和glibc (Linux)并没有很好地合作来创建一个(非内核API) libc标准。

目前,这一小段预处理器代码:

代码语言:javascript
运行
复制
#if defined(__linux__)
#  include <endian.h>
#elif defined(__FreeBSD__) || defined(__NetBSD__)
#  include <sys/endian.h>
#elif defined(__OpenBSD__)
#  include <sys/types.h>
#  define be16toh(x) betoh16(x)
#  define be32toh(x) betoh32(x)
#  define be64toh(x) betoh64(x)
#endif

(在Linux和OpenBSD上测试)应该隐藏差异。它为您提供了这4个平台上的Linux/FreeBSD风格的宏。

使用示例:

代码语言:javascript
运行
复制
  #include <stdint.h>    // For 'uint64_t'

  uint64_t  host_int = 123;
  uint64_t  big_endian;

  big_endian = htobe64( host_int );
  host_int = be64toh( big_endian );

它是目前可用的最“标准C库”的-ish方法。

票数 60
EN

Stack Overflow用户

发布于 2012-11-13 05:44:04

我推荐阅读这篇文章:http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html

代码语言:javascript
运行
复制
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

uint64_t
ntoh64(const uint64_t *input)
{
    uint64_t rval;
    uint8_t *data = (uint8_t *)&rval;

    data[0] = *input >> 56;
    data[1] = *input >> 48;
    data[2] = *input >> 40;
    data[3] = *input >> 32;
    data[4] = *input >> 24;
    data[5] = *input >> 16;
    data[6] = *input >> 8;
    data[7] = *input >> 0;

    return rval;
}

uint64_t
hton64(const uint64_t *input)
{
    return (ntoh64(input));
}

int
main(void)
{
    uint64_t ull;

    ull = 1;
    printf("%"PRIu64"\n", ull);

    ull = ntoh64(&ull);
    printf("%"PRIu64"\n", ull);

    ull = hton64(&ull);
    printf("%"PRIu64"\n", ull);

    return 0;
}

将显示以下输出:

代码语言:javascript
运行
复制
1
72057594037927936
1

如果删除上面的4个字节,您可以使用ntohl()测试这一点。

你也可以在C++中把它变成一个很好的模板化函数,它可以处理任意大小的整数:

代码语言:javascript
运行
复制
template <typename T>
static inline T
hton_any(const T &input)
{
    T output(0);
    const std::size_t size = sizeof(input);
    uint8_t *data = reinterpret_cast<uint8_t *>(&output);

    for (std::size_t i = 0; i < size; i++) {
        data[i] = input >> ((size - i - 1) * 8);
    }

    return output;
}

现在你的128位也安全了!

票数 18
EN

Stack Overflow用户

发布于 2009-05-01 02:01:12

要检测您的字节顺序,请使用以下联合:

代码语言:javascript
运行
复制
union {
    unsigned long long ull;
    char c[8];
} x;
x.ull = 0x0123456789abcdef; // may need special suffix for ULL.

然后,您可以检查x.c[]的内容,以检测每个字节的去向。

为了进行转换,我会使用一次检测代码来查看平台正在使用的字节顺序,然后编写我自己的函数来进行交换。

您可以将其设置为动态,以便代码可以在任何平台上运行(检测一次,然后在转换代码中使用开关来选择正确的转换),但是,如果您只打算使用一个平台,我只需要在一个单独的程序中执行一次检测,然后编写一个简单的转换例程,确保您记录了它只在该平台上运行(或已经过测试)。

下面是我用来演示它的一些示例代码。它已经过测试,虽然不是彻底的,但应该足以让你上手了。

代码语言:javascript
运行
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TYP_INIT 0
#define TYP_SMLE 1
#define TYP_BIGE 2

static unsigned long long cvt(unsigned long long src) {
    static int typ = TYP_INIT;
    unsigned char c;
    union {
        unsigned long long ull;
        unsigned char c[8];
    } x;

    if (typ == TYP_INIT) {
        x.ull = 0x01;
        typ = (x.c[7] == 0x01) ? TYP_BIGE : TYP_SMLE;
    }

    if (typ == TYP_SMLE)
        return src;

    x.ull = src;
    c = x.c[0]; x.c[0] = x.c[7]; x.c[7] = c;
    c = x.c[1]; x.c[1] = x.c[6]; x.c[6] = c;
    c = x.c[2]; x.c[2] = x.c[5]; x.c[5] = c;
    c = x.c[3]; x.c[3] = x.c[4]; x.c[4] = c;
    return x.ull;
}

int main (void) {
    unsigned long long ull = 1;
    ull = cvt (ull);
    printf ("%llu\n",ull);
    return 0;
}

请记住,这只是检查纯大端/小端。如果你有一些奇怪的变量,其中字节以{5,2,3,1,0,7,6,4}的顺序存储,那么cvt()会稍微复杂一点。这样的体系结构不值得存在,但我不会忽视我们在微处理器行业的朋友们的疯狂:-)

还要记住,这在技术上是未定义的行为,因为您不应该通过除最后写入的字段之外的任何字段来访问联合成员。它可能适用于大多数实现,但从纯粹的观点来看,您可能应该咬紧牙关,使用宏来定义您自己的例程,例如:

代码语言:javascript
运行
复制
// Assumes 64-bit unsigned long long.
unsigned long long switchOrderFn (unsigned long long in) {
    in  = (in && 0xff00000000000000ULL) >> 56
        | (in && 0x00ff000000000000ULL) >> 40
        | (in && 0x0000ff0000000000ULL) >> 24
        | (in && 0x000000ff00000000ULL) >> 8
        | (in && 0x00000000ff000000ULL) << 8
        | (in && 0x0000000000ff0000ULL) << 24
        | (in && 0x000000000000ff00ULL) << 40
        | (in && 0x00000000000000ffULL) << 56;
    return in;
}
#ifdef ULONG_IS_NET_ORDER
    #define switchOrder(n) (n)
#else
    #define switchOrder(n) switchOrderFn(n)
#endif
票数 14
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/809902

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档