【问题标题】:Why C memory field reinterpreting through cast differs between regular cast and cast through pointer?为什么通过强制转换重新解释的 C 内存字段在常规强制转换和通过指针强制转换之间有所不同?
【发布时间】:2020-09-06 00:01:36
【问题描述】:

我写了这样的代码示例:

int main(void) {
     double f = 0.1;
     int i, j;

     i = *(int *)(&f);
     j = (int)f;
     printf("%d\n%d\n", i, j); 

     return 0;
}

我预计结果会是一样的。因为我认为通常这些是相同的事情:将一种类型的数据重新解释为另一种类型的数据并获取一种类型的指针,将其转换为另一种类型的指针,然后访问数据。但我得到了:

-1717986918
0

是什么原因?对不起,如果很明显。

【问题讨论】:

  • i 被强制通过指针转换来解释f,就好像它是一个int,但事实并非如此。它甚至不是相同的sizejf 的简单赋值,它被截断为 0,并且强制转换抑制了关于失去意义的编译器警告。
  • 根据@WeatherVane 所说的,i 是一种严格混叠违规,会导致未定义的行为。

标签: c casting reinterpret-cast


【解决方案1】:
j = (int)f;

这会获取f,并以某种方式将其转换为整数值。

i = *(int *)(&f);

这是f地址,并告诉编译器“这是一个整数”,然后将其值存储到i

第二种形式使用原始位,不考虑双精度在内存中的表示形式与整数不同。

编辑

正如 Christian Gibbons 所指出的,这种通过不同类型的指针访问对象的方式是undefined behavior,这意味着您的应用可能会做各种意想不到的事情,甚至运行良好;)

【讨论】:

  • 您还应该指出*(int *)(&f) 表单在未定义的行为中调用
【解决方案2】:

只是补充@Ripi2 的答案。

第一种情况执行转换,因此二进制表示不同。例如,数字3.141516 有代表3 的位和一些代表.141516 的位。当您强制转换为 int 时,编译器只会丢弃小数部分的位,并将剩余位用作整数的最低有效位。因此你得到一个“3”。

对于用户定义的类型,您实际上可以实现自己的转换运算符。 All you have to do 正在您的班级中创建 operator SomeType() const 方法。例如,如果您的类有一个 operator int() const 方法,那么当您将类的对象强制转换为 int 时(包括将对象传递给需要 int 的函数时),将使用该方法。当然,该语言已经包含对普通旧数据的有效转换,例如从浮点到整数。

另一方面,如果您将指针从一种类型转换为另一种类型,编译器将不会执行任何转换。当您尊重指针时,它只会将位于该位置的位视为您询问的类型的二进制表示并向您显示结果,如果您将其转换为不是的东西,这可能是任何东西。这类似于在不知道自己在做什么的情况下使用reinterpret_cast 的危险。

【讨论】:

  • 在这两种情况下,演员都会执行转换。首先,它将double 转换为int。其次,它将double * 转换为int *。通过取消引用的转换指针访问告诉编译器加载这些位,就好像它们是int,而不是转换本身。
  • 在指针的情况下“没有转换”的意思是实际数据(指针指向的内存中的位)没有改变,只有类型。稍后当您决定如何解释这些位时,将使用该类型。
猜你喜欢
  • 2021-05-28
  • 2012-02-10
  • 2015-05-25
  • 2016-07-27
  • 2010-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多