为什么在使用指针初始化用户自定义结构时需要强制类型转换?
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
的类型是 int
而 4
是一个简单的整型常量,可以直接赋给 *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';
您将改为尝试修改字符串文字,并且很可能会遇到分段错误。
我有这个结构定义:
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
的类型是 int
而 4
是一个简单的整型常量,可以直接赋给 *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';
您将改为尝试修改字符串文字,并且很可能会遇到分段错误。