考虑以下代码:
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:英特尔'核心2 Duo' 字节:很少 操作系统:Ubuntu 12.04LTS(64位),Windows 7(64位)答案 0 :(得分:4)
特定于实现类型char
是签名还是未签名。
为char
类型的变量分配0xFF
的值可能会产生255
(如果类型确实未签名)或-1
(如果在大多数实现中类型确实是 signed )(其中char
中的位数为8
)。
值小于或等于0x7F
(127
)的值将适合 unsigned char 和 signed 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
要避免您遇到的问题,请将您的变量显式声明为 signed 或 unsigned ,在这种情况下,将您的值转换为unsigned char
就足够了:
mv.integer_ = static_cast<unsigned char> ('\xFF'); /* 255, NOT -1 */
旁注:
在读取 union 的成员时,您正在调用未定义的行为,该成员不是您写入的最后一个成员。该标准没有具体说明在这种情况下会发生什么。当然,在大多数实现中,它将按预期工作。访问union.mem_[0]
很可能会产生union.integer_
的第一个字节,但这不是保证。
答案 1 :(得分:3)
'\xff'
的类型为char
。 char
是许多平台上的有符号整数类型,因此'\xff
的值为负(-1
而不是255
)。当你将它转换(强制转换)为int
(也是有符号的)时,你得到一个具有相同负值的int。
严格低于0x80
的任何内容都是正面的,并且您会从转换中得到肯定。
答案 2 :(得分:2)
因为'\xff'
是签名字符(char
的默认值在许多体系结构中签名,但并非总是如此) - 当转换为整数时,它会进行符号扩展,使其成为32位(在这种情况下)int
。
在二进制算术中,几乎所有的负表示都使用最高位来表示“这是负的”,并使用某种“反向”逻辑来表示该值。最常见的是使用“二进制补码”,其中没有“负零”。在这种形式中,所有的都是-1
,“最负数”是1后跟很多零,所以8位的0x80是-128,16位的0x8000是-32768,而0x80000000是-2147百万(以及更多数字)。
在这种情况下,解决方案是使用static_cast<unsigned char>('\xff')
。
答案 3 :(得分:1)
基本上,存储在签名的8位字符中的0xff
为-1
。 char
没有signed
或unsigned
说明符是有符号还是无符号取决于编译器和/或平台,在这种情况下似乎是。
转换为int,它保持值-1,存储在32位signed int中的值为0xffffffff
。
0x7f
为127
,其转换为32位整数为0x0000007f
。