转换空指针

18

我在旧的C代码中看到了很多下面这样的写法:

type_t *x = (type_t *) malloc(...);

malloc() 返回的是 void * 类型的指针,为什么还要进行指针类型转换?这是因为旧版本的 C 编译器不支持 void 指针,所以 malloc() 曾经返回 char * 指针。


2
C语言允许这样做,而C++不允许。然而,在C语言编程时,并不意味着您应该强制转换void*。C语言并非C++。 - Joey Adams
1
我在这里问了一个类似的问题:https://dev59.com/dHRB5IYBdhLWcg3wgHWr - Patrick McDonald
4个回答

24
你的解释是正确的。早期的 ANSI C(即“K&R”C)没有隐式转换的 void * 类型。 char * 作为一种伪 void * 类型,但需要使用显式的类型转换。
在现代 C 中,强制类型转换被视为不良做法,因为它可能会抑制对 malloc 缺少原型的编译器警告。在 C++ 中,强制类型转换是必需的(但大多数时候应该使用 new 而不是 malloc)。
更新
我的下面的评论试图解释为什么需要强制转换,有点不清楚,我将在此尝试更好地解释。你可能认为,即使 malloc 返回 char *,也不需要强制转换,因为它类似于:
int  *a;
char *b = a;

但在这个例子中,还需要进行强制类型转换。第二行是对简单赋值运算符(C99 6.5.1.6.1)的约束违规。两个指针操作数需要是兼容类型的。当您将其更改为:

int  *a;
char *b = (char *) a;

限制违规消失(两个操作数现在都具有char *类型),并且结果是明确定义的(用于转换为char指针)。在“相反的情况”下:

char *c;
int  *d = (int *) c;

对于类型转换来说,同样的论点也成立,但是当int *具有比char *更严格的对齐要求时,结果是实现定义

结论:在ANSI之前的时代,类型转换是必需的,因为malloc返回的是char *,而不对转换结果进行强制转换将违反'='运算符的约束条件。


我也认为这个论点是最有说服力的。即使 malloc() 返回 char*,这样的转换在技术上也不是必需的,因为 lvalue 的类型无论如何都无法改变。 - Blagovest Buyukliev
我的评论试图解释说,除了编译器会提示的警告之外,char *c; int *x; x = c; 在技术上是可行的。 - Blagovest Buyukliev
我认为你错了,因为存在对齐问题:根据C99 6.3.2.3(7):“指向对象或不完整类型的指针可以转换为指向不同对象或不完整类型的指针。如果所得到的指针未正确对齐指向的类型,则行为是未定义的。” - schot
“x = c;” 和 “x = (int *) c;” 产生的机器码完全相同吗? - Blagovest Buyukliev
1
@Blagovest Buyukliev:x = c根本不需要编译-它违反了标准中的“应该”条款。编译器拒绝它并将其视为错误而不仅仅是发出警告是合理的。 - caf
显示剩余3条评论

7
这里的问题不是与C语言方言的兼容性,而是C++。在C++中,void指针不能自动转换为任何其他指针类型。因此,如果没有显式转换,这段代码将无法通过C++编译器编译。

3

我不知道malloc曾经返回过char*。

但是,从void*到type_t*(或任何其他类型)的隐式转换并不总是被允许的。因此,需要显式地将其转换为正确的类型。


9
在 C89 标准之前,malloc() 函数返回的是 char * 类型。由于需要一个“通用”的指针类型可以隐式地转换为任何其他指针类型,因此在 C89 中引入了 void * 类型。自 C89 以来,没有必要显式地将 malloc() 函数的结果强制转换为所需的指针类型。 - John Bode
我承认错误。我从未意识到malloc曾经返回char*。好知道。 - abelenky

-3
从malloc()返回的指针是void*类型,那么为什么要进行强制类型转换呢?
恰恰相反,你需要在使用之前将void指针转换为实际类型,因为void*表示该位置存储的数据类型未知。

我并不试图在没有进行类型转换的情况下取消引用一个空指针。这里的重点是lvalue是一个有类型的指针,在赋值之前你仍然需要对rvalue进行类型转换。 - Blagovest Buyukliev
3
在赋值时,void* 类型会自动转换为相应的 type_t* 类型。 - sth
你的论点只是说明了为什么x(在原帖中)必须是type_t*,而不是为什么必须有一个强制转换来分配值。 - James Curran
1
如果在C语言中使用了“cast”这个词,表示使用(type)操作符。在指针被使用之前确实需要进行转换,但是这种转换会隐式地发生。-1表示错误使用了“cast”这个词。 - R.. GitHub STOP HELPING ICE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接