在C / C ++等语言中,当我们这样做时:
char c = 'A';
我们将内存分配给二进制存储号65:
stuff_to_the_left_01000001_stuff_to_the_right
然后,如果我们这样做:
int i = (int) c;
据我了解,我们告诉编译器它应该将位模式解释为stuff_to_the_left_01000001__00000000_00000000_00000000_stuff_to_the_right
,可能会或可能不会是65。
当我们在操作期间执行演员时会发生同样的事情
cout << (int) c << endl;
在上述所有情况中,我得到了字符'A'和十进制65。我是幸运的还是我错过了一些基本的东西?
答案 0 :(得分:2)
C中的强制转换不会重新解释任何内容。它们是价值转换。 (int)c
表示取c
的值并将其转换为int
,这在基本上所有系统上都是无操作。 (如果char
的范围大于int
的范围,则唯一可能无法成为无操作的方式,例如char
和int
是32位但char
是无符号的。)
如果要重新解释值基础的表示(位模式),该值必须首先作为对象(左值)存在,而不仅仅是表达式的值(通常称为“rvalue”,尽管此语言未在C标准)。然后你可以做类似的事情:
*(new_type *)&object;
但是,除了new_type
是字符类型的情况之外,这会通过违反别名规则来调用未定义的行为。 C ++有一种“重新解释强制转换”来执行此操作,这可能会避免破坏别名规则,但由于我不熟悉C ++,我无法向您提供有关它的详细信息。
在C ++示例中,获得不同结果的原因是运算符重载。 (int)'A'
不会更改值或解释方式;相反,具有不同类型的表达式会导致调用operator<<
函数的不同重载。另一方面,在C中,(int)'A'
始终是无操作,因为'A'
的类型int
在C中开头。
答案 1 :(得分:2)
我是幸运的还是我错过了一些基本的东西?
是的,你遗漏了一些基本的东西:编译器没有从内存中读取char
,好像内存代表int
。相反,它会将char
作为字符读取,然后对该值进行符号扩展以适合int
,因此char
-1
变为int
{{ 1}}。符号扩展意味着在扩展的最高有效字节的左侧添加-1
或1
s,具体取决于该数字的符号位。无符号类型始终用零填充 * 。
符号扩展通常通过执行专用硬件指令在寄存器中完成,因此运行速度非常快。
<小时/> * 根据评论中提到的Eric Postpischil,0
类型可以是签名或无签名,具体取决于C实现。
答案 2 :(得分:0)
当你分配一个字符时,左边或右边没有东西。这是八位,仅此而已。那么当你将8位值转换为32位时,你仍然得到65:
0100.0001
至0000.0000 0000.0000 0000.0000 0100.0001
没有魔力,没有运气。
答案 3 :(得分:0)
在你的代码中,“i”有自己的地址,“c”有自己的地址。价值正在从c复制到i。 对于“(int)c”,再次进行同样的操作。虽然编译器为我们做了这些,如下所示。
|--- i ---|- c-|
0x01 0x02 0x03 0x04
+--------------------......
| 00 | 00 | 08 | 08 |......
+--------------------......
如果这是基于指针的分配,那你就是对的。
e.g。
0x01 0x02 0x03
+---------------......
| 07 | 10 | 08 |......
+---------------......
int *p;
char c = 10;
p = &c;
print(*p); //not a real method just something that can print.
这里* p将具有来自mem地址0x02和0x03的组合值。
答案 4 :(得分:-1)
嗯,问题是,这种行为可能会根据您正在编译的平台以及您正在使用的编译器而发生变化。
ISO标准将(int)定义为强制转换。 在这种情况下,您的编译器将解释(int)c,如c ++中的static_cast(c)//
现在,您很幸运,您的编译器将(int)解释为简单的强制转换。它是任何c / c ++编译器的常见行为,但可能会有一些邪恶的,无名的c ++编译器,它会对那个编译器进行重新解释,最终导致不可预测的结果(取决于平台)。 / p>
这就是为什么你应该使用static_cast(c)100%shure 如果你想重新解释它,当然reinterpret_cast(c)
但同样,它通常是c风格的演员,因此c将被转换为整数。