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

Nit*_*wal 5 c pointers structure compound-literals

我有这个结构定义:

typedef struct node_bst
{
  int data;
  struct node_bst *lchild;
  struct node_bst *rchild;
  struct node_bst *parent;
} node_bst;
Run Code Online (Sandbox Code Playgroud)

我试图用这个创建一个指向结构的指针:

node_bst *root;
Run Code Online (Sandbox Code Playgroud)

和像这样分配内存:

root= malloc(sizeof(node_bst));
Run Code Online (Sandbox Code Playgroud)

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

*root= {0, NULL, NULL, NULL};
Run Code Online (Sandbox Code Playgroud)

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

错误:'{'标记之前的预期表达式

我查了一下,发现我需要像这样对它进行类型化:

*root= (node_bst) {0, NULL, NULL, NULL};
Run Code Online (Sandbox Code Playgroud)

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

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

另一件奇怪的事:

int *a= malloc(sizeof(int));
*a= 4;
Run Code Online (Sandbox Code Playgroud)

这很好用.

Vla*_*cow 10

没有铸造.

在这个声明中

*root = (node_bst) {0, NULL, NULL, NULL};
Run Code Online (Sandbox Code Playgroud)

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

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

3由带括号的类型名称后跟括号括起的初始值列表组成的post fi x表达式是复合文字.它提供了一个未命名的对象,其值由初始化列表给出.

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

root->data   = 0;
root->lchil  = NULL;
root->rchil  = NULL;
root->parent = NULL;
Run Code Online (Sandbox Code Playgroud)

至于这个说法

*root= {0, NULL, NULL, NULL};
Run Code Online (Sandbox Code Playgroud)

那么从C的角度看它是无效的.您可以仅在声明中使用支撑初始化.

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


dbu*_*ush 4

这里使用的语法不是类型转换,而是复合文字。这些在C 标准第 6.5.2.5 节中定义:

3由带括号的类型名称和后跟大括号括起来的初始值设定项列表组成的后缀表达式是 复合文字。它提供一个未命名的对象,其值由初始值设定项列表给出。

struct当将 a作为一个整体进行赋值时,复合文字是必需的。

在这种情况下,您不需要此语法:

int *a= malloc(sizeof(int));
*a= 4;
Run Code Online (Sandbox Code Playgroud)

由于*a具有类型int并且4是一个简单的整数常量,可以直接分配给*a

还要注意,涉及指针这一事实是无关紧要的。在这种情况下,您需要执行相同的操作:

node_bst root;
root= (node_bst){0, NULL, NULL, NULL};
Run Code Online (Sandbox Code Playgroud)

这不同于:

node_bst root = {0, NULL, NULL, NULL};
Run Code Online (Sandbox Code Playgroud)

前一种情况是赋值,而后一种情况是初始化。初始化只能在定义变量时完成(即使是在函数之外),而赋值可以随时完成。

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

另外,正如评论中提到的,您仍然可以在初始化中使用复合文字,并且复合文字具有您可以获取其地址的当前范围的生命周期。

这是一个有趣的例子:

char *str = (char[]){ "My string" };
str[3] = 'S';
Run Code Online (Sandbox Code Playgroud)

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

char *str = "My string";
str[3] = 'S';
Run Code Online (Sandbox Code Playgroud)

相反,您将尝试修改字符串文字,并且很可能会出现分段错误。