1

考虑这段代码:

typedef union
{
    int integer_;
    char mem_[4];
} MemoryView;

int main()
{
    MemoryView mv;
    mv.integer_ = (int)'\xff';
    for(int i=0;i<4;i++)
        std::cout << mv.mem_[i]; // output is \xff\xff\xff\xff

    mv.integer_ = 0xff;
    for(int i=0;i<4;i++)
        std::cout << mv.mem_[i]; // output is \xff\x00\x00\x00

    // now i try with a value less than 0x80
    mv.integer_ = (int)'\x7f'
    for(int i=0;i<4;i++)
        std::cout << mv.mem_[i]; // output is \x7f\x00\x00\x00


    mv.integer_ = 0x7f;
    for(int i=0;i<4;i++)
        std::cout << mv.mem_[i]; // output is \x7f\x00\x00\x00

    // now i try with 0x80
    mv.integer_ = (int)'\x80'
    for(int i=0;i<4;i++)
        std::cout << mv.mem_[i]; // output is \x80\xff\xff\xff

    mv.integer_ = 0x80;
    for(int i=0;i<4;i++)
        std::cout << mv.mem_[i]; // output is \x80\x00\x00\x00

}

我用 GCC4.6 和 MSVC2010 测试了它,结果是一样的。当我尝试使用小于 0x80 的值时输出是正确的,但使用大于 0x80 的值时,剩下的三个字节是 '\xff'。

CPU : Intel 'core 2 Duo' Endianness : little OS : Ubuntu 12.04LTS (64bit), Windows 7(64 bit)

4

4 回答 4

4

类型是有符号还是无符号是特定于实现的。char


在大多数实现中(其中的位数是) ,分配一个类型char的变量的值0xFF可能会产生255(如果类型真的是无符号的)或-1(如果类型是真的有符号的)。char8

小于或等于0x7F( 127) 的值将适合unsigned charsigned char,这解释了为什么您会得到您所描述的结果。


#include <iostream>
#include <limits>

int
main (int argc, char *argv[])
{
  std::cerr << "unsigned char: "
            << +std::numeric_limits<unsigned char>::min ()
            << " to "
            << +std::numeric_limits<unsigned char>::max ()
            << ", 0xFF = "
            << +static_cast<unsigned char> ('\xFF')
            << std::endl;

  std::cerr << "  signed char: "
            << +std::numeric_limits<signed char>::min ()
            << " to "
            << +std::numeric_limits<signed char>::max ()
            << ", 0xFF = "
            << +static_cast<signed char> ('\xFF')
            << std::endl;
}

典型输出

unsigned char: 0 to 255, 0xFF = 255
  signed char: -128 to 127, 0xFF = -1

为了规避您遇到的问题,将变量显式声明为有符号无符号,在这种情况下,将您的值转换为 aunsigned char就足够了:

mv.integer_ = static_cast<unsigned char> ('\xFF'); /* 255, NOT -1 */

旁注: 在读取不是您写入的最后一个成员的工会成员时,您正在调用未定义的行为。该标准没有指定在这种情况下会发生什么。当然,在大多数实现下,它会按预期工作。访问很可能会产生 的第一个字节,但这不是保证。union.mem_[0]union.integer_

于 2013-07-27T09:42:15.473 回答
3

的类型'\xff'charchar在很多平台上都是有符号整数类型,所以 的值为'\xff负数(-1而不是255)。当您将其转换(转换)为int(也有符号)时,您会得到一个具有相同负值的 int。

任何严格低于0x80将是积极的,你会从转换中得到积极的。

于 2013-07-27T09:37:14.893 回答
2

因为'\xff'是有符号字符(char在许多体系结构中默认为有符号,但并非总是如此) - 当转换为整数时,它会进行符号扩展,使其成为 32 位(在这种情况下)int

在二进制算术中,几乎所有负数表示都使用最高位来表示“这是负数”,并使用某种“逆”逻辑来表示该值。最常见的是使用“二进制补码”,其中没有“负零”。在这种形式中,全是-1,“最大负数”是 1 后跟很多零,所以 8 位中的 0x80 是 -128,16 位中的 0x8000 是 -32768,0x80000000 是 -21.47 亿(和更多的数字)。

在这种情况下,一个解决方案是使用static_cast<unsigned char>('\xff').

于 2013-07-27T09:37:35.370 回答
1

基本上,0xff存储在有符号的 8 位字符中的是-1. 无符号或说明符是有符号还是char无符号取决于编译器和/或平台,在这种情况下似乎是。signedunsigned

转换为 int,它保持值 -1,它存储在 32 位有符号 int 中0xffffffff

0x7f另一方面存储在 8 位有符号 char is 中127,将其转换为 32 位 int is 0x0000007f

于 2013-07-27T09:37:07.003 回答