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

fel*_*eek 13 c pointers casting

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

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

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

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

int* int_pointer;
char* char_pointer;
int_pointer = malloc(sizeof(int));
*int_pointer = 4;
Run Code Online (Sandbox Code Playgroud)

现在有两种选择:

1.

char_pointer = (char *)int_pointer;
Run Code Online (Sandbox Code Playgroud)

2.

char_pointer = int_pointer;
Run Code Online (Sandbox Code Playgroud)

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

谢谢

oua*_*uah 14

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

C中的指针类型之间没有隐式转换(例如,在算术类型之间) - 具有类型的异常void *.这意味着如果你想将指针转换为另一种指针类型(除了void *),C要求你进行转换.如果您未能执行此操作,则需要实施以发出诊断消息,并且允许转换失败.

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

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

 p = q;  // not valid in C
Run Code Online (Sandbox Code Playgroud)

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

编辑:

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

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


AnT*_*AnT 11

您的教师对共享相同表示的所有指针类型所说的内容通常适用于C语言的实际实现.

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

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

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

然而,你的榜样与char_pointerint_pointer作为提出,不正是说明.该char_pointer = int_pointer;分配简单无效的(如"没有编译").语言不支持不兼容的指针类型之间的隐式转换.此类转换始终需要显式强制转换运算符.

  • @dmckee:是的,`void*`*可以*表示任何数据指针值,但这只是意味着任何数据指针都可以转换为`void*`而不会丢失任何信息.即你可以将任何数据指针`T*`转换为`void*`然后将其转换回`T*`并获得原始的`T*`值.这是由语言保证的.注意,因为`void*`不必在内存中使用与所有其他数据指针类型相同的表示.它可以具有完全不同的表示,只要该表示保证指针值被保留. (2认同)
  • @dmckee:同时,OP的引用做出了更强有力的断言:*"所有指针在内存中的表示方式相同"*.这是一个完全不同的故事.这不是真的.OP的引用声称,除其他外,指针类型之间的转换纯粹是概念性的,它在生成的代码中是无操作的.在大多数实际情况中确实如此,但正式的语言定义表明将某些"T*"转换为"void*"可能涉及一些实际的"工作". (2认同)