将 64 位 Int 转换为 Char[](并返回)
Convert 64bit Int to Char[] (and back)
我编程我想转换一个大端数组(我相信因为我在 Mac 上,整数将是小端)字符(或者更确切地说 uint8_ts) 到 int64_t 并返回。这是我的代码:
int64_t CharsToInt(uint8_t* chars) {
return chars[0] + (chars[1] * 0x100) + (chars[2] * 0x10000) + (chars[3] * 0x1000000) + (chars[4] * 0x100000000) + (chars[5] * 0x10000000000) + (chars[6] * 0x1000000000000) + (chars[7] * 0x100000000000000);
}
void IntToChars(int64_t i, uint8_t* chars) {
for(int k = 0; k < 8; k++) {
chars[k] = i >> k*8;
}
}
int main() {
int64_t x;
unsigned char chars[8];
IntToChars(x, chars);
for (int k = 0; k < 8; k++) {
printf("%0x\n", chars[k]);
}
// little endian
int64_t rv = CharsToInt(chars);
printf("%lld\n", rv);
}
如果 x
是 12,或任何其他零或正数,代码工作得很好,但是如果 x
是负数,它就无法工作。
x
= 12 的输出:
c
0
0
0
0
0
0
0
value: 12
x
= -12 的输出:
f4
ff
ff
ff
ff
ff
ff
ff
value: -4294967308
这似乎与符号的存储和转换方式有关,因为我认为英特尔(我在 Mac)使用 2s-compliment 而不是普通的旧符号位。但是,我真的不知道如何确定这是否属实,如果属实,如何补偿(最好以可移植的方式)。
我知道还有很多其他类似的问题,我已经通读了它们(实际上大部分代码都来自它们),但我仍然无法正常工作,所以我问我自己。
你是对的。 Intel 64 和 IA-32 使用 2 补码表示有符号数。请参阅 Intel 64 and IA-32 Architectures Software Developer’s Manual 第 4.2.1 节。因此,读 FFFFFFFFFFFFFFF4
为 -12 是正确的。在 2 补码表示中,负数通过取相应的正数、反转所有位并加 1 来表示:
12 = 000000000000000C -> FFFFFFFFFFFFFFF3 -> FFFFFFFFFFFFFFF4 = -12
如果我可以添加一些内容,您也可以通过以下操作将您的字符数组转换为 uint64_t
:
int64_t CharsToInt(uint8_t* chars) {
return *(int64_t*)chars;
}
经过更多的折腾,这就是我终于开始工作的(我认为)。它实际上避免了必须一起处理字节顺序和 2s-compliment,通过删除符号并在转换后重新应用它,使用 C 掩码和乘法:
int64_t CharsToInt(uint8_t* chars) {
// Don't modify argument
uint8_t tmp;
tmp = chars[0];
bool neg = false;
if (tmp & 0x80) {
tmp &= 0x7f;
neg = true;
}
int64_t rv = chars[7] + (chars[6] * 0x100) + (chars[5] * 0x10000) + (chars[4] * 0x1000000) + (chars[3] * 0x100000000) + (chars[2] * 0x10000000000) + (chars[1] * 0x1000000000000) + (tmp * 0x100000000000000);
if (neg) {
rv *= -1;
}
return rv;
}
void IntToChars(int64_t i, uint8_t* chars) {
int64_t num = i;
bool neg = false;
if (i & 0x8000000000000000) {
neg = true;
num *= -1;
}
chars[0] = num / 0x100000000000000;
num = num % 0x100000000000000;
chars[1] = num / 0x1000000000000;
num = num % 0x1000000000000;
chars[2] = num / 0x10000000000;
num = num % 0x10000000000;
chars[3] = num / 0x100000000;
num = num % 0x100000000;
chars[4] = num / 0x1000000;
num = num % 0x1000000;
chars[5] = num / 0x10000;
num = num % 0x10000;
chars[6] = num / 0x100;
num = num % 0x100;
chars[7] = num;
if (neg) {
chars[0] += 0x80;
}
}
我编程我想转换一个大端数组(我相信因为我在 Mac 上,整数将是小端)字符(或者更确切地说 uint8_ts) 到 int64_t 并返回。这是我的代码:
int64_t CharsToInt(uint8_t* chars) {
return chars[0] + (chars[1] * 0x100) + (chars[2] * 0x10000) + (chars[3] * 0x1000000) + (chars[4] * 0x100000000) + (chars[5] * 0x10000000000) + (chars[6] * 0x1000000000000) + (chars[7] * 0x100000000000000);
}
void IntToChars(int64_t i, uint8_t* chars) {
for(int k = 0; k < 8; k++) {
chars[k] = i >> k*8;
}
}
int main() {
int64_t x;
unsigned char chars[8];
IntToChars(x, chars);
for (int k = 0; k < 8; k++) {
printf("%0x\n", chars[k]);
}
// little endian
int64_t rv = CharsToInt(chars);
printf("%lld\n", rv);
}
如果 x
是 12,或任何其他零或正数,代码工作得很好,但是如果 x
是负数,它就无法工作。
x
= 12 的输出:
c
0
0
0
0
0
0
0
value: 12
x
= -12 的输出:
f4
ff
ff
ff
ff
ff
ff
ff
value: -4294967308
这似乎与符号的存储和转换方式有关,因为我认为英特尔(我在 Mac)使用 2s-compliment 而不是普通的旧符号位。但是,我真的不知道如何确定这是否属实,如果属实,如何补偿(最好以可移植的方式)。
我知道还有很多其他类似的问题,我已经通读了它们(实际上大部分代码都来自它们),但我仍然无法正常工作,所以我问我自己。
你是对的。 Intel 64 和 IA-32 使用 2 补码表示有符号数。请参阅 Intel 64 and IA-32 Architectures Software Developer’s Manual 第 4.2.1 节。因此,读 FFFFFFFFFFFFFFF4
为 -12 是正确的。在 2 补码表示中,负数通过取相应的正数、反转所有位并加 1 来表示:
12 = 000000000000000C -> FFFFFFFFFFFFFFF3 -> FFFFFFFFFFFFFFF4 = -12
如果我可以添加一些内容,您也可以通过以下操作将您的字符数组转换为 uint64_t
:
int64_t CharsToInt(uint8_t* chars) {
return *(int64_t*)chars;
}
经过更多的折腾,这就是我终于开始工作的(我认为)。它实际上避免了必须一起处理字节顺序和 2s-compliment,通过删除符号并在转换后重新应用它,使用 C 掩码和乘法:
int64_t CharsToInt(uint8_t* chars) {
// Don't modify argument
uint8_t tmp;
tmp = chars[0];
bool neg = false;
if (tmp & 0x80) {
tmp &= 0x7f;
neg = true;
}
int64_t rv = chars[7] + (chars[6] * 0x100) + (chars[5] * 0x10000) + (chars[4] * 0x1000000) + (chars[3] * 0x100000000) + (chars[2] * 0x10000000000) + (chars[1] * 0x1000000000000) + (tmp * 0x100000000000000);
if (neg) {
rv *= -1;
}
return rv;
}
void IntToChars(int64_t i, uint8_t* chars) {
int64_t num = i;
bool neg = false;
if (i & 0x8000000000000000) {
neg = true;
num *= -1;
}
chars[0] = num / 0x100000000000000;
num = num % 0x100000000000000;
chars[1] = num / 0x1000000000000;
num = num % 0x1000000000000;
chars[2] = num / 0x10000000000;
num = num % 0x10000000000;
chars[3] = num / 0x100000000;
num = num % 0x100000000;
chars[4] = num / 0x1000000;
num = num % 0x1000000;
chars[5] = num / 0x10000;
num = num % 0x10000;
chars[6] = num / 0x100;
num = num % 0x100;
chars[7] = num;
if (neg) {
chars[0] += 0x80;
}
}