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

在C中,您可以将intfloat和指针等简单数据类型转换为这些数据类型。

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

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

 #include  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; } 

在我的系统上输出是

 1: 3, 2: 1079194419 

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

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

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

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

 int i1 = (int) (*pf); 

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

 int i2 = *((int*) pf); 

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

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

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

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

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

如果先取消引用,稍后再转换为int,则会得到从float到int的强制转换的常规(截断)行为。 如果首先转换为指向int的指针,然后取消引用,则标准不会定义行为。 通常它表现在将包含float的内存解释为int。 请参阅http://en.wikipedia.org/wiki/IEEE_754-2008了解其运作方式。

当然可以! Casting告诉编译器如何查看内存的某些部分。 然后当您访问内存时,它会尝试根据您告诉它的方式解释数据。 使用以下示例更容易理解它。

 int main() { char A[] = {0, 0, 0, 1 }; int p = *((int*)A); int i = (int)*A; printf("%d %d\n", i, p); return 0; } 

32位小端机器的输出为0 16777216 。 这是因为(int*)A告诉编译器将A视为指向整数的指针,因此当你取消引用A时,它会查看从A开始的4个字节(as sizeof(int) == 4) 。 在考虑了字节序之后,4个字节的内容被评估为16777216.另一方面, *A取消引用A得到0(int)*A转换得到0。

演员,然后取消引用意味着“假装我指向另一件事,然后得到另一件应该指向的东西”。

取消引用,然后转换意味着“得到我实际指向的东西,然后通过通常的规则将其转换为另一个东西”。

“通常的规则”可以改变位,以获得逻辑上代表相同值的另一种类型的值。 假装你指着你实际上没有指向的东西不能。

int在内存中不表示与float相同。 你所看到的是编译器认为指针是一个int并且它看着32位内存,认为当它实际上找到一个未定义的浮点部分时会找到一个int,这对于某些非常有用。大数字。

根据标准的6.5 / 7,粗略地说,存储值必须与有效类型或字符类型兼容。 所以,我认为语句int i2 = *((int*) pf)没有明确定义。