昨天我上课了,在某个时候讲师正在谈论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)最终会改变内存中的指针格式(如果是的话,你能给出一个机器的例子吗?)?
由于
答案 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语言本身的角度来看,这是不正确的。
char *
指针的表示方式与void *
指针相同。T
(const
,volatile
,restrict
)的指针的表示方式与指向不合格T
的指针相同。 就是这样。没有其他保证。这意味着就语言本身而言,int *
指针与double *
指针的表示形式不同。指向struct S
的指针与指向union U
的指针的表示方式不同。
但是,您提供的char_pointer
和int_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。