关于linux:C ++中的64位ntohl()?

您所在的位置:网站首页 setw未定义 关于linux:C ++中的64位ntohl()?

关于linux:C ++中的64位ntohl()?

2023-09-07 09:17| 来源: 网络整理| 查看: 265

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

我的问题是我需要将64位整数(在我的情况下,这是一个无符号的long long)从big endian转换为little endian。现在,我需要进行特定的转换。但是如果目标平台为大端字节序,该函数(如ntohl())不会转换我的64位值,那就更好了。 (我宁愿避免添加自己的预处理器魔术来执行此操作)。

我可以使用什么?我想要一些标准的东西(如果存在的话),但我愿意接受实施建议。我已经看到过去使用联合完成这种类型的转换。我想我可以有一个unsigned long long和一个char [8]的联合。然后相应地交换字节。 (显然会在大端字节序的平台上中断)。

相关讨论 您的平台是什么? 大多数系统具有特定于平台的BE到LE转换例程。 如果失败,您可以轻松编写一个。 看看我对另一个问题的答复 就我的2cts而言,它是用C标准清楚地写的(不知道是89,还是99),一个长的长度足以存储一个指针。 但是,短语在C ++标准中不出现。 我见过的Linux编译器尊重,在64位版本上,long是64位。 但是,Microsoft选择了一种奇怪的解决方案,其中到处都是32位长。 @JasonCoco您首先问了这个问题,我想这是我首先问的问题,我在下面发布了示例答案,我想这就是您要解决的问题。 对于那些感兴趣的人,这里给出了该问题的实际答案

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

不幸的是,在2009年,OpenBSD,FreeBSD和glibc(Linux)并没有很好地协同工作来为此创建一个(非内核API)libc标准。

当前,这段简短的预处理器代码:

12345678910#if defined(__linux__) #  include #elif defined(__FreeBSD__) || defined(__NetBSD__) #  include #elif defined(__OpenBSD__) #  include #  define be16toh(x) betoh16(x) #  define be32toh(x) betoh32(x) #  define be64toh(x) betoh64(x) #endif

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

使用示例:

1234567  #include    // For 'uint64_t'   uint64_t  host_int = 123;   uint64_t  big_endian;   big_endian = htobe64( host_int );   host_int = be64toh( big_endian );

这是目前最"标准的C库"式方法。

相关讨论 这不适用于android(定义__linux__但提供了openbsd api) @Stefan:那太恐怖了:(

我建议阅读以下内容:http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647#include #include #include 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" ", ull);     ull = ntoh64(&ull);     printf("%"PRIu64" ", ull);     ull = hton64(&ull);     printf("%"PRIu64" ", ull);     return 0; }

将显示以下输出:

1231 72057594037927936 1

如果删除高4个字节,则可以使用ntohl()进行测试。

您也可以将其转换为C ++中很好的模板化函数,该函数可以在任何大小的整数上工作:

1234567891011121314template static inline T hton_any(const T &input) {     T output(0);     const std::size_t size = sizeof(input);     uint8_t *data = reinterpret_cast(&output);     for (std::size_t i = 0; i > ((size - i - 1) * 8);     }     return output; }

现在您的128位安全了!

相关讨论 我认为您的模板版本已损坏,它忽略了最后一个字节。为了解决这个问题,我更改了size = sizeof(T);和input >> ((size-i-1)*8)。 纯粹是对于大于寄存器大小的类型的编译器抽象如何将部分存储在内存中的猜测。谁说他们想严格遵守小字节序或大字节序?它甚至可以是不依赖于平台的设计,例如它在一个体系结构上是自然的,而在另一个体系结构上则是不自然的。没关系,因为大整数的"加载"代码是相同的,并且可移植。但是此选择取决于编译器。 以uint8_t身份访问内存违反了严格的别名规则,并且是未定义的行为。 有没有办法使其与结构一起使用?将处理应用于每个字节...在第一行(T的开头)产生错误,并且缺少operator>>。

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

12345union {     unsigned long long ull;     char c[8]; } x; x.ull = 0x0123456789abcdef; // may need special suffix for ULL.

然后,您可以检查x.c[]的内容以检测每个字节到达的位置。

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

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

这是我摘录的一些示例代码。尽管没有进行全面的测试,但是应该足以使您入门。

123456789101112131415161718192021222324252627282930313233343536373839#include #include #include #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 ",ull);     return 0; }

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

还请记住,这在技术上是不确定的行为,因为除了最后一个写入的字段外,您不应通过任何其他字段访问工会成员。它可能适用于大多数实现,但从纯粹的角度来看,您可能应该硬着头皮,使用宏定义自己的例程,例如:

1234567891011121314151617// 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)          | ((value & 0x00000000FF000000ull)


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3