使用Malloc在C中定义结构
我之前问了一个关于使用malloc定义结构的问题 。 这是大多数人给出的答案:
struct retValue* st = malloc(sizeof(*st));
我向朋友展示了我的代码,我们遇到了绊脚石。 有人可以解释为什么这段代码有效吗? 从我的观点来看,当你使用malloc时没有定义* st,因此那里可能存在任何类型的垃圾。 它应该是malloc(sizeof(struct retValue))
谢谢你的帮助
Sizeof查看赋予它的表达式的类型,它不评估表达式。 因此,您只需要确保声明表达式中使用的变量,以便编译器可以推断出它们的类型。
在您的示例中,st已经被声明为指向struct-ret-retValue的指针。 因此,编译器能够推导出表达式“* st”的类型。
虽然它看起来不像已在您的代码中声明,但编译器已经为您处理了它。 代码中的所有声明都将移动到编译器出现的块的开头。 假设你写
说明编译器可用知识的一种方法是查看它生成的中间输出。 考虑这个示例代码……
struct retValue {long int a, long int b}; ... printf("Hello World!\n"); struct retValue* st = malloc(sizeof(*st));
使用gcc作为示例,并在test.c的main()函数中使用上面的代码,让我们通过运行来查看中间输出…
gcc -fdump-tree-cfg test.c
编译器将生成文件test.c.022t.cfg – 看看它,你会看到
[ ... removed internal stuff ...] ;; Function main (main) Merging blocks 2 and 3 main (argc, argv) { struct retValue * st; int D.3097; void * D.3096; # BLOCK 2 # PRED: ENTRY (fallthru) __builtin_puts (&"Hello World!"[0]); D.3096 = malloc (16); st = (struct retValue *) D.3096; D.3097 = 0; return D.3097; # SUCC: EXIT }
注意声明如何移动到块的开头,malloc的参数已经被表示表达式计算类型的大小的实际值替换。 正如评论中所指出的那样,声明被移到块顶部的事实是编译器的实现细节。 但是,编译器能够执行此操作并将正确的大小插入malloc all的事实表明编译器能够从输入中推断出必要的信息。
我个人更喜欢将实际的类型名称作为sizeof的参数,但这可能是编码风格的问题,我认为这种一致性胜过个人偏好。
sizeof
运算符实际上并不计算它的操作数 – 它只是查看它的类型。 这是在编译时而不是运行时完成的。 因此,可以在分配变量之前安全地执行它。
重要的是结构类型的声明/定义,而不是这类类的对象的定义。 到达malloc
,编译器将遇到声明/定义,否则会遇到编译器错误。
sizeof
不评估其操作数的事实是一个副问题。
一个小问题:记住我们在向sizeof
提供类型名称时需要括号,如下所示:
sizeof(struct retValue);
而不是对象,我们只是做:
sizeof *st;
看标准:
6.5.3一元运算符语法
unary-expression: [...] sizeof unary-expression sizeof ( type-name )
在C中, sizeof
是一个运算符,不会计算其参数。 这可能导致“有趣”的影响,C新手不一定会预料到。 我在回答 “最奇怪的语言特征”问题时更详细地提到了这一点。