在C中,如果我对一个指针进行转换和取消引用,那么我先做哪一个是否重要?

sle*_*ske 13 c casting undefined-behavior

在C语言中,你可以投既简单数据类型,例如int,float以及指向这些.

现在我假设如果你想从一个类型的指针转​​换为另一个类型的值(例如从*floatto转换int),则转换和解除引用的顺序无关紧要.也就是说,对于变量float* pf,你有(int) *pf == *((int*) pf).有点像数学中的交换性......

然而,情况似乎并非如此.我写了一个测试程序:

#include <stdio.h>
int main(int argc, char *argv[]){
  float f = 3.3;
  float* pf = &f;
  int i1 = (int) (*pf);
  int i2 = *((int*) pf);
  printf("1: %d, 2: %d\n", i1, i2);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

在我的系统上输出是

1: 3, 2: 1079194419
Run Code Online (Sandbox Code Playgroud)

因此,转换指针似乎与转换值的方式不同.

这是为什么?为什么第二个版本不符合我的想法呢?

这是平台依赖的,还是我以某种方式调用未定义的行为?

dav*_*vep 16

以下说将浮点数设为pf并将其转换为整数.这里的转换是将float转换为整数的请求.编译器生成用于将float值转换为整数值的代码.(将浮点值转换为整数是一件"正常"事情.)

int i1 = (int) (*pf);
Run Code Online (Sandbox Code Playgroud)

下面首先说FORCE编译器认为pf指向一个整数(并忽略pf是指向float的指针),然后得到整数值(但它不是整数值).这是一件奇怪且危险的事情.在这种情况下,铸件禁用正确的转换.编译器在内存中执行位的简单副本(生成垃圾).(也可能存在内存对齐问题!)

int i2 = *((int*) pf);
Run Code Online (Sandbox Code Playgroud)

在第二个语句中,您不是"转换"指针.你告诉编译器内存指向什么(在这个例子中,这是错误的).

这两个陈述做的事情非常不同!

请记住,有时候c使用相同的语法来描述不同的操作.

=============

请注意,double是C中的默认浮点类型(数学库通常使用双参数).


eta*_*ion 5

如果您先取消引用,然后再转换为 int,您将获得从 float 到 int 转换的常见(截断)行为。如果您首先转换为指向 int 的指针,然后取消引用,则该行为不是由标准定义的。通常它表现为将包含 float 的内存解释为 int。请参阅http://en.wikipedia.org/wiki/IEEE_754-2008了解其原理。

  • 通常它表现为“严格别名”违规,导致读取错误数据或根本没有数据,至少在现代 gcc 上是这样。 (3认同)
  • 只是这里是 C,你应该使用 `-std=c99` 等。 (2认同)