不在C中转换指针会导致问题?

昨天我上课了,在某个时候讲师正在谈论C代码。 他说:

在C中制作指针的目的是什么? 唯一的目的是使编译器正确解释指针操作(例如,添加int指针将导致与添加char指针不同的偏移量)。 除此之外,没有区别:所有指针在内存中的表示方式相同,无论指针指向int值,char值,short值等等。 因此,转换指针不会修改内存中的任何内容,它只会帮助程序员执行与他正在处理的指针类型更相关的操作。

但是,我已经阅读,特别是在Stack Overflow中,这不是100%真实。 我已经读过,在一些奇怪的机器中,不同类型的指针可以以不同的方式存储在内存中。 在这种情况下,如果将代码编译为此类机器,则不将指针更改为正确的类型可能会导致问题。

基本上,这是我正在谈论的那种代码。 考虑以下代码:

int* int_pointer; char* char_pointer; int_pointer = malloc(sizeof(int)); *int_pointer = 4; 

现在有两种选择:

1。

 char_pointer = (char *)int_pointer; 

2。

 char_pointer = int_pointer; 

案例2的代码可能成为一个问题? 制作演员表(案例1)最终会改变内存中的指针格式(如果是的话,你能给出一个机器的例子吗?)?

谢谢

您的讲师所说的关于共享相同表示的所有指针类型通常适用于C语言的实际实现。

但是,从抽象C语言本身的角度来看,这是不正确的。 C语言保证

  1. char *指针的表示方式与void *指针相同。
  2. 指向T类型的限定版本( constvolatilerestrict )的指针以与指向不合格T指针相同的方式表示。
  3. 所有结构类型的指针都以相同的方式表示。
  4. 指向所有联合类型的指针的表示方式相同。

就这些。 没有其他保证。 这意味着就语言本身而言, int *指针具有与double *指针不同的表示。 而指向struct S指针与指向union U指针的表示方式不同。

但是,如图所示,使用char_pointerint_pointer示例并不完全是说明性的。 char_pointer = int_pointer; 赋值只是无效(如“不编译”)。 语言不支持不兼容的指针类型之间的隐式转换。 此类转换始终需要显式强制转换运算符。

不在C中转换指针会导致问题?

C中的指针类型之间没有隐式转换(例如,在算术类型之间) – 具有void *类型的exception。 这意味着如果要将指针转换为另一种指针类型( void *除外),则C要求您进行转换。 如果您不这样做,则需要实施以发出诊断消息,并且允许转换失败。

有些编译器足够好(或变态不够),不需要强制转换。 它们通常表现得就像你明确地放置了演员表。

  char *p = NULL; int *q = NULL; p = q; // not valid in C 

总之,出于可移植性原因,在将指针转换为指针时应始终放置强制转换。

编辑:

外部可移植性,一个不进行强制转换的示例可能会导致您遇到实际问题,例如使用可变参数函数。 让我们假设一个实现,其中char *的大小大于int *的大小。 假设函数期望一个参数的类型为char * 。 如果要传递int *的参数,则必须将其转换为char * 。 如果你没有强制转换它,当函数访问char *对象时,对象的某些位将具有不确定的值,并且bevahior将是未定义的。

一个有点接近的例子是printf ,如果用户无法转换为void *转换说明符的参数void * ,C表示它会调用未定义的行为。

你的教授说的听起来是对的。

…(例如,添加int指针将导致与添加char指针不同的偏移量)

这是正确的,因为假设int是4个字节而char是1个字节,向int指针添加2将导致将指针移动8个字节,而向char指针添加2将仅将指针移动到下一个字节2立场。

除此之外,没有区别:所有指针在内存中的表示方式相同,无论指针指向int值,char值,short值等等。

这是事实,机器不区分char和int指针,这些是编译器要处理的问题。 你的教授也提到了:

唯一的目的是使编译器正确解释指针操作

因此,转换指针不会修改内存中的任何内容,它只会帮助程序员执行与他正在处理的指针类型更相关的操作。

这也是事实。 转换不会修改内存,只会更改内存的一部分解释方式。

转换指针不会改变指针值,它只告诉编译器如何处理指针。 指针本身只是一个数字,它没有类型。 它是存储具有类型的指针的变量。

两种分配指针的方法没有区别(如果编译器允许你进行分配)。 无论源指针变量的类型如何,都将根据赋值后的目标变量的类型使用指针。

您根本无法将int指针存储在char指针变量中。 一旦值存储在变量中,它就没有一个指向int的指针。

直接使用值时,强制转换指针很重要,例如:

 int* int_pointer; int_pointer = malloc(sizeof(int)); *int_pointer = 4; char c; c = *(char*)int_pointer; 

转换指针意味着取消引用它会从该位置读取char,而不是int。

从void *转换到我的程序中需要的类型(例如int *,char *,struct x *)对我来说很有意义。 但是,跨越其他类型(即int *到char *等)的转换可能会成为问题(由于int,char等的偏移量不同)。 如果这样做,请小心。

但是……要专门回答您的问题,请考虑以下事项:

 int_pointer = malloc(2 * sizeof(int)); // 2 * 4 bytes on my system. *int_pointer = 44; *(int_pointer + 1 )= 55; printf("Value at int_pointer = %d\n", *int_pointer); // 44 printf("Value at int_pointer + 1 = %d\n", *(int_pointer + 1)); // 55 

(上面的偏移量将以4个字节为增量。)

 //char_pointer = int_pointer; // Gives a warning ... char_pointer = (char*)int_pointer; // No warning. printf("Value at char_pointer = %d\n", *char_pointer); // 0 printf("Value at char_pointer = %d\n", *(char_pointer+1)); // 0 printf("Value at char_pointer = %d\n", *(char_pointer+2)); // 0 printf("Value at char_pointer = %d\n", *(char_pointer+3)); // 44 <== 

四个字节被分配给int值44.44的二进制表示是00101100 ...剩余的3个字节都是0。 因此,当使用char *指针访问时,我们一次增加1个字节并获得上述值。

指针的转换对于说编译器如何执行指针运算至关重要。

例如,如果x是指向内存2001的字符指针,x ++应该转到2002,但如果x是一个整数指针x ++应该是2003

因此,如果未对指针进行类型转换,则编译器将无法正确执行指针arithematic。