C/C++ 将 64 位整数转换为字符数组
C/C++ Converting a 64 bit integer to char array
我有以下简单程序,它使用联合在 64 位整数与其对应的字节数组之间进行转换:
union u
{
uint64_t ui;
char c[sizeof(uint64_t)];
};
int main(int argc, char *argv[])
{
u test;
test.ui = 0x0123456789abcdefLL;
for(unsigned int idx = 0; idx < sizeof(uint64_t); idx++)
{
cout << "test.c[" << idx << "] = 0x" << hex << +test.c[idx] << endl;
}
return 0;
}
我期望的输出是:
test.c[0] = 0xef
test.c[1] = 0xcd
test.c[2] = 0xab
test.c[3] = 0x89
test.c[4] = 0x67
test.c[5] = 0x45
test.c[6] = 0x23
test.c[7] = 0x1
但我实际得到的是:
test.c[0] = 0xffffffef
test.c[1] = 0xffffffcd
test.c[2] = 0xffffffab
test.c[3] = 0xffffff89
test.c[4] = 0x67
test.c[5] = 0x45
test.c[6] = 0x23
test.c[7] = 0x1
我在 Ubuntu LTS 14.04 with GCC 上看到了这个。
一段时间以来,我一直在努力解决这个问题。为什么 char 数组的前 4 个元素显示为 32 位整数,并在它们前面加上 0xffffff?为什么只有前 4 个,为什么不是全部?
有趣的是,当我使用数组写入流(这是整个事情的最初目的)时,写入了正确的值。但是逐个字符比较数组显然会导致问题,因为前 4 个字符不等于 0xef、0xcd 等等。
它是 unsigned char 与 signed char 及其转换为整数
使用 unsigned char 或使用 test.c[idx] & 0xff
以避免在将 char value > 0x7f
转换为 int 时进行符号扩展。
使用 char
不是正确的做法,因为它可能是 signed
或 unsigned
。使用 unsigned char
.
union u
{
uint64_t ui;
unsigned char c[sizeof(uint64_t)];
};
一元加号导致 char
提升为 int
(整数提升)。因为您已经签署了字符,所以该值将按原样使用,其他字节将反映出来。
不是只有这四个是int,它们都是。您只是从表示中看不到它,因为未显示前导零。
使用 unsigned char
或 & 0xff
进行推广以获得理想的结果。
char
由于前置的一元运算符 +
被提升为 int
。 .由于您的 chars
是 signed
,任何具有最高 by 设置为 1
的元素都被解释为负数并提升为具有相同负值的整数。有几种不同的方法可以解决这个问题:
- 删除
+
:... << test.c[idx] << ...
。这可能会将 char 打印为字符而不是数字,因此可能不是一个好的解决方案。
- 声明
c
为 unsigned char
。这会将其提升为 unsigned int
.
- 在传递之前显式转换
+test.c[idx]
:... << (unsigned char)(+test.c[idx]) << ...
- 使用二进制
&
将整数的高位字节设置为零:... << +test.c[idx] & 0xFF << ...
。无论 char
如何提升,这只会显示最低位字节。
我有以下简单程序,它使用联合在 64 位整数与其对应的字节数组之间进行转换:
union u
{
uint64_t ui;
char c[sizeof(uint64_t)];
};
int main(int argc, char *argv[])
{
u test;
test.ui = 0x0123456789abcdefLL;
for(unsigned int idx = 0; idx < sizeof(uint64_t); idx++)
{
cout << "test.c[" << idx << "] = 0x" << hex << +test.c[idx] << endl;
}
return 0;
}
我期望的输出是:
test.c[0] = 0xef
test.c[1] = 0xcd
test.c[2] = 0xab
test.c[3] = 0x89
test.c[4] = 0x67
test.c[5] = 0x45
test.c[6] = 0x23
test.c[7] = 0x1
但我实际得到的是:
test.c[0] = 0xffffffef
test.c[1] = 0xffffffcd
test.c[2] = 0xffffffab
test.c[3] = 0xffffff89
test.c[4] = 0x67
test.c[5] = 0x45
test.c[6] = 0x23
test.c[7] = 0x1
我在 Ubuntu LTS 14.04 with GCC 上看到了这个。
一段时间以来,我一直在努力解决这个问题。为什么 char 数组的前 4 个元素显示为 32 位整数,并在它们前面加上 0xffffff?为什么只有前 4 个,为什么不是全部?
有趣的是,当我使用数组写入流(这是整个事情的最初目的)时,写入了正确的值。但是逐个字符比较数组显然会导致问题,因为前 4 个字符不等于 0xef、0xcd 等等。
它是 unsigned char 与 signed char 及其转换为整数
使用 unsigned char 或使用 test.c[idx] & 0xff
以避免在将 char value > 0x7f
转换为 int 时进行符号扩展。
使用 char
不是正确的做法,因为它可能是 signed
或 unsigned
。使用 unsigned char
.
union u
{
uint64_t ui;
unsigned char c[sizeof(uint64_t)];
};
一元加号导致 char
提升为 int
(整数提升)。因为您已经签署了字符,所以该值将按原样使用,其他字节将反映出来。
不是只有这四个是int,它们都是。您只是从表示中看不到它,因为未显示前导零。
使用 unsigned char
或 & 0xff
进行推广以获得理想的结果。
char
由于前置的一元运算符 +
被提升为 int
。 .由于您的 chars
是 signed
,任何具有最高 by 设置为 1
的元素都被解释为负数并提升为具有相同负值的整数。有几种不同的方法可以解决这个问题:
- 删除
+
:... << test.c[idx] << ...
。这可能会将 char 打印为字符而不是数字,因此可能不是一个好的解决方案。 - 声明
c
为unsigned char
。这会将其提升为unsigned int
. - 在传递之前显式转换
+test.c[idx]
:... << (unsigned char)(+test.c[idx]) << ...
- 使用二进制
&
将整数的高位字节设置为零:... << +test.c[idx] & 0xFF << ...
。无论char
如何提升,这只会显示最低位字节。