struct node{
int w;
int x;
}
struct node *item;
我在不需要malloc后读作类型转换。为什么会这样?
1)item = malloc(sizeof(*item));
2)item = malloc(sizeof(struct node));
3)item = (struct node *) malloc(sizeof(struct node));
答案 0 :(得分:2)
在这种特殊情况下,所有方法都会给出完全相同的结果。
1:
item = malloc(sizeof(*item));
*item
是struct node
,因此sizeof(*item)
将返回struct node
的大小,该行将为单个节点分配内存。这有时优先于2),就好像你要将item
重构为不同的类型一样,你不需要改变这一行。
2:
item = malloc(sizeof(struct node));
这一行相当不言自明。如前所述,如果item
要更改类型,则需要更改此行,因为分配的内存量将不再正确(除非是纯粹的运气)。
3:
malloc
会返回指向void
或void *
的指针。即使没有强制转换,它也会自动转换为正确的类型。事实上,有几个人(包括我自己)会建议你强烈不要使用类型转换器。有关详细信息,请阅读this question
答案 1 :(得分:2)
让我们看看这些:
1) item = malloc(sizeof(*item));
上面的代码是C中的经典方法。使用calloc
可能更安全,因为它将清除分配给所有位零的结构。如果稍后向结构添加字段并忘记在分配的每个实例中的malloc
之后的代码中初始化,这将是一个有用的副作用。我会这么推荐:
1 preferred) item = calloc(1, sizeof(*item));
以下替代方案假设item
是指向struct node
的指针。当您第一次编写代码时可能会出现这种情况,如果您稍后更改item
的类型,或者如果您将代码复制到item
不同类型的其他位置并且您忘记了做出改变。
2) item = malloc(sizeof(struct node));
最后一个选项展示了另一个问题:
3) item = (struct node *) malloc(sizeof(struct node));
转换malloc
的返回值的问题在其他地方已经有很多评论。它在C ++中是必要的,并且在C语言中被认为是无用的并且可能容易出错。在某种情况下它可能实际上有用的目的:
#define alloc_node() ((struct node*)calloc(1, sizeof(node)))
item = alloc_node();
这里建议使用强制转换来检测错误类型的分配。如果item
不是指向struct node
的指针,编译器会抱怨并防止该错误。
总之,首选calloc
优先于malloc
,更喜欢sizeof(*item)
优先于sizeof(node node)
。如果上下文不允许使用sizeof(*dst)
,如上所述或在表达式或函数参数中,则使用强制转换。
答案 2 :(得分:2)
从功能上讲,这三者都是等价的。
在风格上,1是首选选项(至少由我和许多其他C程序员)。请注意,sizeof
是一个运算符,而不是一个函数,只有在操作数是类型名称时才需要括号。所以你可以写sizeof *item
而不是sizeof (*item)
- 除了可读性之外,它们不会伤害任何东西。另请注意,sizeof
不会尝试评估其参数(它不会尝试取消引用item
);它所做的只是计算结果类型所需的字节数,它在编译时而不是运行时完成。
就C而言,你应该不投射malloc
的结果。从1989年的标准来看,它不再是必要的; malloc
返回void *
,可以将其分配给任何其他指针类型,而无需显式转换 1 。
根据C89标准,如果您忘记包含malloc
或在范围内没有stdlib.h
声明,那么投放malloc
的结果可能会取消有用的诊断效果。 C89仍然允许隐式int
声明;如果编译器在没有声明的情况下在代码中看到函数调用,则假定函数返回int
值。如果你不使用强制转换,编译器会抱怨你试图为指针对象分配一个整数值。使用强制转换,编译器可以在没有诊断的情况下编译代码,但是您要将指针值转换为int
并再次返回指针,这可能会也可能不起作用。
C99标准摆脱了隐式int
声明,因此不再是问题;如果忘记加入stdlib.h
,您是否会获得诊断。出于可读性和可维护性的原因,你仍然应该抛弃演员;它所做的就是添加无用的视觉混乱。如果您更改了目标的声明(从struct foo *
到struct bar *
),那么您也必须更新演员阵容,这只是额外的工作,如果您忘了这样做然后它就是一个bug。无论您对item = malloc( sizeof *item )
的类型做出哪些更改,item
总是做正确的事情而无需任何进一步的维护。
C ++,与C语言不同,具有不同的规则, not 允许您在没有显式强制转换的情况下将void *
分配给另一个指针类型,因此将< / em>必须在这种情况下转换malloc
的结果。如果您要从C迁移到C ++并且无法重做所有动态内存管理代码(这是唯一在C ++中使用malloc
的借口,那么这是一个问题码)。当然,您应该不在C ++中使用malloc
/ calloc
/ realloc
;要么使用其中一个标准容器,要么使用new
运算符。
<小时/> 1 - 在C89标准之前,
malloc
,calloc
和realloc
都返回char *
,因此如果 ,则需要 目标是一种不同的指针类型。不幸的是,即使不再需要习惯,这种习惯仍然存在
答案 3 :(得分:1)
表单2很糟糕,因为您可能会意外分配错误的内存量。
表单1和表单3都允许程序员目视检查分配是否正确:
item = malloc(sizeof(*item));
// ^^^^ ^^^^^
item = (struct node *) malloc(sizeof(struct node));
// ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
一旦您了解到varname
应该使用*varname
,或者(Typename *)
应该使用(Typename)
,那么您更有可能快速检测到尺寸错误。
如the main thread about this所述,在C89中,表格3是危险的,而表格1是安全的。在C99及更高版本中,该基本原理不太引人注目,但是Form 1具有更紧凑,并且需要更少维护的优点。如果item
的类型被更改,那么任何Form 3行都将触发编译错误,而Form 1行只会自动使用更新后的类型。