首页 > 解决方案 > C - 不兼容的指针类型分配:为什么它是一个警告?

问题描述

我正在看 K&R 第 2 版,它说(在第 5.4 节中):

除了 void *,将一个类型的指针分配给另一种类型的指针而不进行强制转换是不合法的。

但是,gcc 和 clang 在执行此操作时只会发出警告,而不是编译器错误:

int *ip;
char *cp;

ip = cp;

我在 gcc 手册上没有看到任何说明这是默认编译器扩展的内容。使用 C++ 编译器确实会引发编译错误。

请注意,这本书在 A6.6 节中似乎自相矛盾,它说

指向一种类型的指针可以转换为指向另一种类型的指针。

尽管我给了它怀疑的好处,因为它可能指的是使用显式强制转换从指针类型转换为另一种。

标签: c

解决方案


int *ip;
char *cp;

ip = cp;

赋值是违反约束的,这意味着符合标准的编译器必须发出诊断,就像它必须为语法错误所做的那样。(有关简单分配的要求,请参阅http://port70.net/~nsz/c/c11/n1570.html#6.5.16.1。)该诊断可能是非致命警告。C 标准从不要求拒绝代码,除非它有#error指令。它没有将代码称为“合法”或“非法”。

如果您使用例如gcc -std=c11 -pedantic-errors. 请注意,默认情况下 gcc 不是完全符合标准的 C 编译器,尽管在这种情况下它的行为是符合标准的。

通过强制转换(显式转换),分配将是合法的:

ip = (int*)cp;

但如果 的值cp不确定或转换导致无效int*值(例如由于对齐),则可能会导致未定义的行为。

K&R 中的描述是正确的,尽管措辞有点不正式。它说:

除了 void *,将一个类型的指针分配给另一种类型的指针而不进行强制转换是不合法的。如果“合法”是指“不违反约束或语法规则”,这是正确的。C 标准本身并没有使用“合法”这个词,但是说某事违反了约束就等于说某事是非法的。

是的,这个:

指向一种类型的指针可以转换为指向另一种类型的指针。确实是指使用强制转换的转换——或者在转换为和从的情况下不使用强制转换void*

(我个人的偏好是将语法错误和约束违规视为致命错误,但大多数编译器默认情况下相对宽松。这可能是出于历史原因。在语言的早期版本中,将一种类型的指针分配给没有强制转换的另一种类型的指针是有效的,并且从来没有一个好时机通过拒绝旧代码来破坏它。)


推荐阅读