转换基元时的内存解释

Memory interpretation while casting primitives

本文关键字:内存 解释 转换      更新时间:2023-10-16

在像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。我是幸运还是错过了一些基本的东西?

C 中的强制转换不会重新解释任何东西。它们是价值转换。 (int)c的意思是取c的值并将其转换为int,这基本上在所有系统上都是无操作的。(它不能成为无操作的唯一方法是如果char的范围大于int的范围,例如,如果charint都是32位的,但char是无符号的。

如果要重新解释值背后的表示形式(位模式),则该值必须首先作为对象(左值)存在,而不仅仅是表达式的值(通常称为"rvalue",尽管这种语言在 C 标准中未使用)。然后,您可以执行以下操作:

*(new_type *)&object;

但是,除非new_type是字符类型,否则这会通过违反别名规则来调用未定义的行为。C++有一种"重新解释强制转换"来做到这一点,大概可以避免违反混叠规则,但由于我不熟悉C++,我无法为您提供有关它的好细节。

在C++示例中,获得不同结果的原因是运算符重载。 (int)'A'不会更改值或其解释方式;相反,具有不同类型的表达式会导致调用operator<<函数的不同重载。另一方面,在 C 中,(int)'A' 始终是无操作的,因为'A'在 C 中具有以类型 int 开头。

我是幸运还是错过了一些基本的东西?

是的,您缺少一些基本的东西:编译器不会从内存中读取char,就好像内存表示int一样。相反,它将char读取为 char,然后对值进行符号扩展以适应int,因此char -1也变得int -1。符号扩展意味着在要扩展的最有效字节的左侧添加 1 s 或 0 s,具体取决于该数字的符号位。无符号类型始终用零*填充。

符号扩展通常通过执行专用的硬件指令在寄存器中完成,因此运行速度非常快。


*正如 Eric Postpischil 在评论中指出的那样,char类型可能是有符号的,也可以是无符号的,具体取决于 C 实现。

当你分配一个字符时,没有东西在左边或右边。这是八位,仅此而已。因此,当您将 8 位值转换为 32 位时,您仍然得到 65:

0100.00010000.0000 0000.0000 0000.0000 0100.0001

没有

魔法,没有运气。

在你的代码中,"i"有自己的地址,"c"有自己的地址。值正在从 c "复制"到 i。至于"(int)c",同样的事情也一样。尽管编译器为我们做到了这一点,如下所示。

     |--- i ---|- c-|  
 0x01 0x02 0x03 0x04
+--------------------......
| 00 | 00 | 08 | 08 |......  
+--------------------......

如果这是基于指针的分配,那么您是正确的。

例如

 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 的值。

嗯,问题是,此行为可能会根据您编译的平台和您使用的编译器而改变。

ISO 标准将 (int) 定义为铸件。在这种情况下,编译器将解释 (int)c,如 static_cast(c)//在 c++ 中

现在,你很幸运,你的编译器将 (int) 解释为一个简单的强制转换。这是任何 c/c++ 编译器的常见行为,但可能存在一些邪恶的、无名的 c++ 编译器,它们会对该编译器进行重新解释,最终导致不可预测的结果(取决于平台)。

这就是为什么你应该使用static_cast(c)是100%舒尔如果你想重新解释它,当然reinterpret_cast(c)

但是,同样,它通常是 C 样式的强制转换,因此 C 将被转换为整数。