我有一个unsigned char数组,表示网络字节顺序的128位数。我如何有效地将其转换为主机字节顺序(在本例中为x86_64)?
在endian.h中似乎没有任何可用的宏,并且我单独转换高64位和低64位的尝试不起作用。我发现绝对有效的唯一方法就是这样的循环:
unsigned __int128 num = 0;
for (int i = 0; i < 16; i++) {
num = (num << 8) | byte[i];
}
我最终做了以下事情:
union {
unsigned char b[MD5_DIGEST_LENGTH];
uint64_t d[2];
unsigned __int128 q;
} digest;
MD5((const unsigned char *)str, length, digest.b);
uint64_t tmp = digest.d[0];
digest.d[0] = be64toh(digest.d[1]);
digest.d[1] = be64toh(tmp);
/* digest.q is now in native byte order */
答案 0 :(得分:3)
如果您可以轻松获得高和低__int64
s,那么您可以反转并交换它们。否则,您可能需要单独查看每个字节。
答案 1 :(得分:2)
union _128_as_32 {
unsigned __int128 v;
unsigned __int32 d[4];
} u1, u2;
u1.v = num;
u2.d[3] = ntohl(u1.d[0]);
u2.d[2] = ntohl(u1.d[1]);
u2.d[1] = ntohl(u1.d[2]);
u2.d[0] = ntohl(u1.d[3]);
// do something with u2.v
如果你的环境有betoh64 / be64toh(linux / bsd endian.h),你可以使用
union _128_as_64 {
unsigned __int128 v;
unsigned __int64 q[2];
} u1, u2;
u1.v = num;
u2.q[1] = betoh64(u1.q[0]);
u2.q[0] = betoh64(u1.q[1]);
// do something with u2.v
看到你可能正在处理IN6地址,你应该已经有了ntohl系列功能。
H.T.H。
答案 2 :(得分:2)
由于您明确说过x86_64,您可以转换为__m128i
并分别使用PSHUFB指令或_mm_shuffle_epi8
。注意正确对齐数据(虽然编译器应该已经正确对齐__int128
),因此编译器可以使用MOVDQA(gcc非常擅长这一点,如果可能的话,它会这样做)。
您需要为<tmmintrin.h>
添加_mm_shuffle_epi8
。
请注意,需要一个(可能很慢)的回退实现,因为2003 - 2004年左右的一些早期AMD64处理器没有SSE3支持。
答案 3 :(得分:1)
如果您知道重新移位字节的模式,则可以使用复合文字。首先,我要声明一个联合类型,只是为了避免一些打字。
typedef union conv {
uint128_t i;
uint8_t c[16];
} conv;
然后你需要一些怪物表达
#define swapped128(n) \
((conv const){ \
.c = { \
[0] = 0xFF & (n >> xx) \
.... \
[15] = 0xFF & (n >> xx)\
} \
})
您必须将xx
替换为与该字节的移位值对应的值。
现在你的交换值只是swapped(n).i
,一个好的编译器应该自己找出用于所有这些的汇编程序指令。
答案 4 :(得分:0)
效率不高;但
unsigned __int128 htonllll(unsigned __int128 v) {
union { unsigned long lv[4]; unsigned __int128 llv; } u;
u.lv[0] = htonl(v >> 96);
u.lv[1] = htonl(v >> 64);
u.lv[2] = htonl(v >> 32);
u.lv[3] = htonl(v & 0xFFFFFFFFULL);
return u.llv;
}
unsigned __int128 ntohllll(unsigned __int128 v) {
union { unsigned long lv[4]; unsigned __int128 llv; } u;
u.llv = v;
return ((unsigned __int128)ntohl(u.lv[0]) << 96) | (unsigned __int128)ntohl(u.lv[1]) << 64) | (unsigned __int128)ntohl(u.lv[2]) << 32) | (unsigned __int128)ntohl(u.lv[3]);
}