2015-09-01 58 views
5

我有一个使用一个联合到一个64位整数,其相应的字节数组之间的转换如下简单的程序:C/C++转换一个64位整数为char阵列

union u 
{ 
    uint64_t ui; 
    char c[sizeof(uint64_t)]; 
}; 

int main(int argc, char *argv[]) 
{ 
    u test; 
    test.ui = 0xabcdefLL; 
    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 

我与GCC看到了这个在Ubuntu 14.04 LTS。

我一直在试图让我的头在这一段时间了。为什么字符数组的前4个元素显示为32位整数,并且0xffffff预置于它们?为什么只有前4个,为什么不是全部?有趣的是,当我使用数组写入流(这是整个事物的原始目的)时,写入了正确的值。但是通过char比较char数组显然会导致问题,因为前4个字符不等于0xef,0xcd等等。

+0

转换为'(char *)'然后读取4个字节...? – SteJ

+0

没有变化。此外,我总是可以用0x000000ff掩码char来获得期望的值。我只是对这种行为背后的原因感兴趣。 – tickferno

+2

显然你的实现已经签署了字符。正常整数升级将签名扩展。 – ewd

回答

3

使用char不是正确的做法,因为它可能是signedunsigned。使用unsigned char

union u 
{ 
    uint64_t ui; 
    unsigned char c[sizeof(uint64_t)]; 
}; 
+0

解决了这个问题。现在的问题是,将数组写入流会给出错误,因为数据流只接受'char *'而不接受'unsigned char *'加上我真的不喜欢总是使用'reinterpret_cast' ... – tickferno

+1

@tickferno,如果您需要帮助,请发布另一个专门解决流媒体问题的问题。 –

0

它是无符号的字符VS签署char和其铸造为整数

1

使用或者无符号的字符,或者使用test.c[idx] & 0xff避免符号扩展当char value > 0x7f转换为int。

0

一元加号导致char被提升到一个int(积分的推广)。因为你已经签名了字符,所以这个值将被用作这样的字符,其他字节将反映这个值。

这不是真的,只有四个是整数,他们都是。由于没有显示前导零,因此您不会从表示中看到它。

可以使用unsigned char s或& 0xff进行促销以获得所需的结果。

2

char由于前置的一元运算符+而被提升为int。 。由于您的charssigned,因此最高设置为1的任何元素都会被解释为负数并被提升为具有相同负值的整数。有几种不同的方法来解决这个问题:

  1. 删除+... << test.c[idx] << ...。这可能会将字符打印为字符而不是数字,因此可能不是一个好的解决方案。
  2. 声明cunsigned char。这会将其推广到unsigned int
  3. 显式强制+test.c[idx]才能通过:... << +test.c[idx] & 0xFF << ...... << (unsigned char)(+test.c[idx]) << ...
  4. 使用二进制&设置整数的高位字节为零。无论char如何升级,这将只显示最低位字节。
+0

char在<<运算符中未被提升,这是由于一元+运算符。如果从代码中删除一元+,可以很容易地看到这一点。 –

+0

删除一元+运算符打印字符“直接”,但我对他们的实际十六进制值感兴趣(十六进制运算符不会帮助否则)。还有以下失败:'test.c [0] == 0xef' – tickferno

+0

良好的通话。据此编辑。 –