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

时间:2015-05-13 20:10:25

标签: c pointers casting

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

  

在C中制作指针的目的是什么?唯一的目的   是让编译器正确解释指针操作   (例如,添加int指针将导致不同的偏移量   而不是添加一个字符指针)。除此之外,没有区别:所有指针在内存中的表示方式相同,无论指针指向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)最终会改变内存中的指针格式(如果是的话,你能给出一个机器的例子吗?)?

由于

6 个答案:

答案 0 :(得分:14)

  

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

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

有些编译器足够好(或变态不够)不需要强制转换。它们的行为通常就像你明确地放置演员一样。

 char *p = NULL;
 int *q =  NULL;

 p = q;  // not valid in C

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

修改

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

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

答案 1 :(得分:11)

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

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

  1. char *指针的表示方式与void *指针相同。
  2. 指向合格版本Tconstvolatilerestrict)的指针的表示方式与指向不合格T的指针相同。
  3. 所有结构类型的指针都以相同的方式表示。
  4. 指向所有联合类型的指针代表相同。
  5. 就是这样。没有其他保证。这意味着就语言本身而言,int *指针与double *指针的表示形式不同。指向struct S的指针与指向union U的指针的表示方式不同。

    但是,您提供的char_pointerint_pointer的示例并不完全是说明性的。 char_pointer = int_pointer;赋值完全无效(如"不编译")。语言不支持不兼容的指针类型之间的隐式转换。此类转换始终需要显式的强制转换操作符。

答案 2 :(得分:3)

你的教授说的是对的。

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

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

除此之外,没有区别:无论指针指向int值,char值,short值还是其他什

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

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

  

因此,投射指针不会修改内存中的任何内容,它会   只是帮助程序员进行与操作更相关的操作   他正在处理的指针式。

这是真的。转换不会修改内存,只会更改内存的一部分解释。

答案 3 :(得分:2)

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

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

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

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

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

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

答案 4 :(得分:2)

从void *转换到我的程序中需要的类型(例如int *,char *,struct x *)对我来说很有意义。但是,跨越其他类型(即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 <==

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

答案 5 :(得分:1)

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

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

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