在C ++ 64位ntohl()?
htonl()
的手册页似乎暗示你最多只能使用它32位的值。 (实际上, ntohl()
被定义为unsigned long,在我的平台上是32位。我想如果unsigned long是8个字节,它可以用于64位int)。
我的问题是我需要从大端到小端转换64位整数(在我的情况下,这是一个无符号长整数)。 现在,我需要做具体的转换。 但是如果函数(如ntohl()
)不能转换我的64位值(如果目标平台是WAS大端ntohl()
它会更好。 (我宁愿避免添加我自己的预处理器魔术来做到这一点)。
我可以使用什么? 如果它存在,我希望有标准的东西,但我愿意接受实施建议。 我已经看到过去使用工会完成的这种类型的转换。 我想我可以有一个无符号long long和char [8]的联合。 然后相应地交换字节。 (显然会在大端的平台上打破)。
文档:Linux上的man htobe64
(glibc> = 2.9)或FreeBSD。
不幸的是,在2009年的一次尝试中,OpenBSD,FreeBSD和glibc(Linux)并没有很顺利地为此创建一个(非内核API)libc标准。
目前,这个短暂的预处理器代码:
#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风格的宏。
使用示例:
#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库”方法。
我会推荐阅读:http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
#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;
}
将显示以下输出:
1
72057594037927936
1
如果删除高4字节,可以用ntohl()来测试。
你也可以把它变成一个很好的C ++模板化函数,它可以处理任何大小的整数:
template <typename T>
static inline T
hton_any(const T &input)
{
T output(0);
const std::size_t size = sizeof(input) - 1;
uint8_t *data = reinterpret_cast<uint8_t *>(&output);
for (std::size_t i = 0; i < size; i++) {
data[i] = input >> ((size - i) * 8);
}
return output;
}
现在你的128位安全了!
要检测您的字节顺序,请使用以下联合:
union {
unsigned long long ull;
char c[8];
} x;
x.ull = 0x0123456789abcdef; // may need special suffix for ULL.
然后你可以检查xc[]
的内容来检测每个字节的位置。
为了完成转换,我会使用一次检测代码来查看平台使用的是什么endian - ness,然后编写我自己的函数做交换。
你可以使它成为动态的,以便代码可以在任何平台上运行(一次检测一次,然后在你的转换代码中使用一个开关来选择正确的转换),但是如果你只打算使用一个平台,我只需要做在单独的程序中检测一次,然后编写一个简单的转换例程,确保记录它只在该平台上运行(或已经过测试)。
这里有一些示例代码是为了说明它。 它已经通过测试,但不够彻底,但应该足以让你开始。
#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 ("%llun",ull);
return 0;
}
请记住,这只是检查纯大/小端。 如果你有一些奇怪的变体,例如{5,2,3,1,0,7,6,4}的顺序存储的字节, cvt()
会比较复杂。 这样的架构不应该存在,但我并没有在微处理器行业中折扣我们的朋友的愚蠢:-)
另外请记住,这在技术上是未定义的行为,因为您不应该通过写入最后一个字段以外的任何字段来访问联合成员。 它可能适用于大多数实现,但为了纯粹的观点,你应该只是咬紧牙关,用宏来定义你自己的例程,如:
// 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
链接地址: http://www.djcxy.com/p/24349.html
下一篇: Performance problem with Euler problem and recursion on Int64 types