在C中投射指针的规则是什么?

K&R没有超过它,但他们使用它。 我试着通过编写一个示例程序来看它是如何工作的,但是效果并不好:

#include <stdio.h> int bleh (int *); int main(){ char c = '5'; char *d = &c; bleh((int *)d); return 0; } int bleh(int *n){ printf("%d bleh\n", *n); return *n; } 

它编译,但我的打印语句吐出垃圾variables(每次我调用该程序时,它们是不同的)。 有任何想法吗?

在思考指针时, 绘制图表是有帮助的。 指针是一个箭头,指向内存中的一个地址,带有一个标签,指示值的types。 该地址指示在哪里看,types指示要采取什么。 投射指针会改变箭头上的标签,但不会改变箭头指向的位置。

main中的d是一个chartypes的指针。 char是一个字节的内存,所以当d被解引用时,你得到的是一个字节的内存的值。 在下图中,每个单元格代表一个字节。

 -+----+----+----+----+----+----+- | | c | | | | | -+----+----+----+----+----+----+- ^~~~ | char d 

当你把dint* ,你就是说d真的指向一个int值。 在大多数系统上,一个int占用4个字节。

 -+----+----+----+----+----+----+- | | c | ?₁ | ?₂ | ?₃ | | -+----+----+----+----+----+----+- ^~~~~~~~~~~~~~~~~~~ | int (int*)d 

当你解引用(int*)d ,你会得到一个由这四个字节的内存决定的值。 你得到的价值取决于这些细胞标记的是? ,以及int如何在内存中表示。

PC是小端的 ,这意味着int的值是这样计算的(假设它跨越4个字节): * ((int*)d) == c + ?₁ * 2⁸ + ?₂ * 2¹⁶ + ?₃ * 2²⁴ 。 所以你会发现虽然值是垃圾,但是如果用hex打印( printf("%x\n", *n) ),最后两位总是35 (这是字符'5' )。

一些其他的系统是big-endian,并在另一个方向上排列字节: * ((int*)d) == c * 2²⁴ + ?₁ * 2¹⁶ + ?₂ * 2⁸ + ?₃ 。 在这些系统上,你会发现以hex打印的值始终 35 。 一些系统的大小与4个字节不同。 less数几个系统以不同的方式排列int ,但是你不太可能遇到它们。

根据您的编译器和操作系统的不同,您可能会发现每次运行该程序时该值都会有所不同,或者在对源代码进行轻微调整时总是会发生变化。

在某些系统中,一个int值必须存储在一个4(或2或8)倍数的地址中。 这被称为alignment要求。 根据c的地址是否正确alignment,程序可能会崩溃。

与你的程序相反,当你有一个int值并且指向它的时候会发生什么。

 int x = 42; int *p = &x; 
 -+----+----+----+----+----+----+- | | x | | -+----+----+----+----+----+----+- ^~~~~~~~~~~~~~~~~~~ | int p 

指针p指向一个int值。 箭头上的标签正确地描述了内存单元中的内容,因此在解引用它时不会有任何意外。

 char c = '5' 

char (1字节)被分配在堆栈的地址0x12345678

 char *d = &c; 

你获得c的地址并将其存储在d ,所以d = 0x12345678

 int *e = (int*)d; 

您强制编译器假定0x12345678指向一个int ,但是int不只是一个字节( sizeof(char) != sizeof(int) )。 根据体系结构甚至其他值可以是4或8个字节。

所以当你打印指针的值时,整数被认为是通过取第一个字节(即c )和其他连续的字节在栈上,这只是垃圾为您的意图。

在C中投射指针通常是无效的。有几个原因:

  1. 对准。 由于alignment的考虑,有可能目标指针types不能表示源指针types的值。 例如,如果int *本质上是4字节alignment的,则将char *int *将会丢失较低的位。

  2. 别名。 通常禁止访问对象,除非通过对象的正确types的左值。 有一些例外,但是除非你非常了解他们,否则你不想这样做。 请注意,如果实际取消引用指针(将*->运算符应用于该运算符,或者将其传递给将其取消引用的函数),则别名只是一个问题。

铸造指针没问题的主要情况是:

  1. 目标指针types指向字符types时。 指向字符types的指针保证能够表示指向任何types的指针,并且如果需要的话成功地将其返回到原始types。 指向void( void * )的指针与指向字符types的指针完全相同,只是不允许对其进行取消引用或对其进行算术运算,并且它会自动转换为其他指针types以及不需要转换,所以指向void的指针通常比用于此目的的字符types的指针更可取。

  2. 当目标指针types是一个指向结构types的指针时,其结构types的成员与原始指向的结构types的初始成员完全匹配。 这对于C中的各种面向对象的编程技术是有用的

在语言要求方面,其他一些不明确的情况在技术上是可行的,但是存在问题并且最好避免。

我怀疑你需要一个更一般的答案:

在C中没有关于指针的规则! 该语言可以让您将指针指向任何其他指针,而无需评论。

但事情是:没有数据转换或做任何事情! 它完全是您自己的责任,系统不会在演员阵容后误解数据 – 这通常会导致运行时错误。

所以,当它完全由你来注意,如果数据是从一个铸造的指针使用的数据是兼容的!

C针对性能进行了优化,因此缺less指针/引用的运行时reflection性。 但这是有代价的 – 作为程序员的你必须更好地照顾你正在做的事情。 你必须知道你自己,如果你想要做的是“合法的”

你有一个指向char的指针。 所以,正如你的系统知道的,在这个内存地址上有一个sizeof(char)空间的char值。 当你将它强制转换为int* ,你将使用sizeof(int)数据,所以你将把char和一些内存垃圾以整数的forms打印出来。

垃圾值实际上是由于你在声明之前调用了函数bleh()

在c ++的情况下,你会得到编译错误,但在c中,编译器假定函数的返回types是int ,而你的函数返回一个指向整数指针。

查看更多信息: http : //www.geeksforgeeks.org/g-fact-95/