为什么在使用指针初始化用户自定义结构时需要强制类型转换?

Why do I need to type cast when initializing a user-defined structure using pointer?

我有这个结构定义:

typedef struct node_bst
{
  int data;
  struct node_bst *lchild;
  struct node_bst *rchild;
  struct node_bst *parent;
} node_bst;

我尝试使用以下方法创建指向结构的指针:

node_bst *root;

并像这样为其分配内存:

root= malloc(sizeof(node_bst));

现在,为了初始化其中的数据项,我尝试了这个语句(从通常的结构变量初始化中得到提示):

*root= {0, NULL, NULL, NULL};

但是编译器抛出了一个错误

error: expected expression before ‘{’ token

我查了一下,发现我需要这样打字:

*root= (node_bst) {0, NULL, NULL, NULL};

现在它工作正常,但我的问题是,为什么我需要这样做?

我希望编译器已经知道 root 是指向 node_bst 类型结构变量的指针。那么为什么需要对右值进行类型转换?

还有一件奇怪的事:

int *a= malloc(sizeof(int));
*a= 4;

这很好用。

没有铸造。

在此声明中

*root = (node_bst) {0, NULL, NULL, NULL};

使用了所谓的复合文字 (node_bst) {0, NULL, NULL, NULL} 对应于类型 node_bst 的对象,并且该对象被分配给对象 *root

来自 C 标准(6.5.2.5 复合文字)

3 A postfix expression that consists of a parenthesized type name followed by a brace-enclosed list of initializers is a compound literal. It provides an unnamed object whose value is given by the initializer list.

另一种方法是只分配动态分配对象的每个数据成员。例如

root->data   = 0;
root->lchil  = NULL;
root->rchil  = NULL;
root->parent = NULL;

至于这个说法

*root= {0, NULL, NULL, NULL};

那么从C的角度来看是无效的。您只能在声明中使用花括号初始化。

如果您将该程序编译为 C++ 程序,则该语句将有效。

此处使用的语法不是类型转换,而是复合文字。这些在 C standard:

的第 6.5.2.5 节中定义

3 A postfix expression that consists of a parenthesized type name followed by a brace-enclosed list of initializers is a compound literal. It provides an unnamed object whose value is given by the initializer list.

struct作为一个整体赋值时需要复合字面量。

在这种情况下你不需要这个语法:

int *a= malloc(sizeof(int));
*a= 4;

因为 *a 的类型是 int4 是一个简单的整型常量,可以直接赋给 *a.

另请注意,涉及指针这一事实无关紧要。在这种情况下你需要做同样的事情:

node_bst root;
root= (node_bst){0, NULL, NULL, NULL};

这不同于:

node_bst root = {0, NULL, NULL, NULL};

前者是赋值,后者是初始化。初始化只能在定义变量时进行(即使在函数之外),而赋值可以在任何时候进行。

初始化语法(参见标准的第 6.7.9 节)仅允许用大括号括起来的值列表,而赋值需要复合文字。

此外,如评论中所述,您仍然可以在初始化中使用复合文字,并且复合文字具有当前作用域的生命周期,您可以获取其地址。

这是一个有趣的例子:

char *str = (char[]){ "My string" };
str[3] = 'S';

这里修改的是复合字面量,这是允许的。但是如果你这样做:

char *str = "My string";
str[3] = 'S';

您将改为尝试修改字符串文字,并且很可能会遇到分段错误。