为什么编码器将结构指针的值分配给静态结构?
Why did coder assign value of struct pointer to a static struct?
抱歉,如果这是重复的,在这种情况下我找不到合适的关键字进行搜索。
这是参考我正在处理的一些旧的 (MUD) 代码,粘贴在下面。我对下面代码的 foo_zero
和 *foo = foo_zero
部分的目的感到困惑。这是它在整个代码库中使用的模式。我的 猜测 是一种将 foo
的所有成员初始化为 zero/NULL 的方法,而无需显式设置它们。
typedef struct FOO {
int buzz;
char *bazz;
} FOO;
FOO *init_foo(void)
{
static FOO foo_zero;
FOO *foo;
foo = malloc(sizeof(*foo));
*foo = foo_zero; // <-- why?
return foo;
}
其实这个声明
static FOO foo_zero;
相当于下面的
static FOO foo_zero = { .buzz = 0, .bazz = 0 };
所以在这个赋值语句中
*foo = foo_zero;
指针 foo 指向的对象被零初始化,方式与静态变量相同 foo_zero。
函数return指向零初始化对象的指针。
对于这个简单的例子,如果你不使用 malloc,你可以获得几乎相同的效果
使用 calloc.
FOO *init_foo(void)
{
return calloc( 1, sizeof( struct FOO ) );;
}
但有时需要进行不平凡的初始化。所以你展示的方法是有意义的。例如
struct FOO
{
size_t n;
char s[10];
};
struct FOO * init_foo( void )
{
static struct FOO default_foo = { .n = 6, .s = "Hello" };
struct FOO *foo = malloc( sizeof( *foo ) );
if ( foo ) *foo = default_foo;
return foo;
}
是的,行
static FOO foo_zero;
和
*foo = foo_zero;
安排 init_foo()
分配的 struct FOO
的每个新实例都被初始化,就好像有人说过
struct FOO new_foo = { 0 };
具体而言,所有整数字段将初始化为 0,所有浮点字段将初始化为 0.0,所有指针字段将初始化为空指针(又名 NULL
,或 nullptr
在 C++ 中)。
这是一个很好的技术,因为它比其他技术更简单,严格来说,更便携。
评论中有关于其他可能性的讨论
foo = malloc(sizeof(*foo));
memset(foo, 0, sizeof(*foo));
或
foo = calloc(1, sizeof(*foo));
这两个都会将全新的 struct FOO
初始化为 all-bits-0。这里的微妙问题——非常微妙以至于许多程序员根本不会称之为问题——是处理器 and/or 操作系统理论上可以表示 0.0 的浮点值,或者一个空指针,其位模式不是全位 0。
但是如果你使用的是这样的处理器,那么
float f = 0;
或
char *p = 0;
会做正确的事情,用正确的零值初始化变量,即使它不是全位 0。对于 struct FOO
这样的聚合,做
struct FOO new_foo = { 0 };
等价于用 0 显式初始化它的每个成员,这意味着你得到正确的零值,即使那不是全位 0。最后,任何时候你声明一个具有静态持续时间的变量,如
static FOO foo_zero;
你会得到一个隐式初始化,就像你说的那样 = { 0 };
,因此默认(静态)初始化无论如何也会给你那些正确的零值。
如果您仍然对 calloc
的全位 0 保证感到好奇,可以在 question 7.31 of the C FAQ list.
中阅读更多相关信息
为什么要复杂化?
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef struct {
int buzz;
char *bazz;
} FOO;
init_foo()
上面实际上只是 returns 在堆上创建了新的 foo。一切干净。因此,让我们这样做吧:
static inline FOO * new_foo(void)
{
return calloc(1,sizeof(FOO));
}
使用与检查:
int main (void)
{
FOO * foo = new_foo();
printf("buzz: %d, bazz: %s", foo->buzz, foo->bazz );
free(foo);
return 42;
}
Godbolt 显示新结构 FOO 很好地为空
Program returned: 42
buzz: 0, bazz: (null)
抱歉,如果这是重复的,在这种情况下我找不到合适的关键字进行搜索。
这是参考我正在处理的一些旧的 (MUD) 代码,粘贴在下面。我对下面代码的 foo_zero
和 *foo = foo_zero
部分的目的感到困惑。这是它在整个代码库中使用的模式。我的 猜测 是一种将 foo
的所有成员初始化为 zero/NULL 的方法,而无需显式设置它们。
typedef struct FOO {
int buzz;
char *bazz;
} FOO;
FOO *init_foo(void)
{
static FOO foo_zero;
FOO *foo;
foo = malloc(sizeof(*foo));
*foo = foo_zero; // <-- why?
return foo;
}
其实这个声明
static FOO foo_zero;
相当于下面的
static FOO foo_zero = { .buzz = 0, .bazz = 0 };
所以在这个赋值语句中
*foo = foo_zero;
指针 foo 指向的对象被零初始化,方式与静态变量相同 foo_zero。
函数return指向零初始化对象的指针。
对于这个简单的例子,如果你不使用 malloc,你可以获得几乎相同的效果 使用 calloc.
FOO *init_foo(void)
{
return calloc( 1, sizeof( struct FOO ) );;
}
但有时需要进行不平凡的初始化。所以你展示的方法是有意义的。例如
struct FOO
{
size_t n;
char s[10];
};
struct FOO * init_foo( void )
{
static struct FOO default_foo = { .n = 6, .s = "Hello" };
struct FOO *foo = malloc( sizeof( *foo ) );
if ( foo ) *foo = default_foo;
return foo;
}
是的,行
static FOO foo_zero;
和
*foo = foo_zero;
安排 init_foo()
分配的 struct FOO
的每个新实例都被初始化,就好像有人说过
struct FOO new_foo = { 0 };
具体而言,所有整数字段将初始化为 0,所有浮点字段将初始化为 0.0,所有指针字段将初始化为空指针(又名 NULL
,或 nullptr
在 C++ 中)。
这是一个很好的技术,因为它比其他技术更简单,严格来说,更便携。
评论中有关于其他可能性的讨论
foo = malloc(sizeof(*foo));
memset(foo, 0, sizeof(*foo));
或
foo = calloc(1, sizeof(*foo));
这两个都会将全新的 struct FOO
初始化为 all-bits-0。这里的微妙问题——非常微妙以至于许多程序员根本不会称之为问题——是处理器 and/or 操作系统理论上可以表示 0.0 的浮点值,或者一个空指针,其位模式不是全位 0。
但是如果你使用的是这样的处理器,那么
float f = 0;
或
char *p = 0;
会做正确的事情,用正确的零值初始化变量,即使它不是全位 0。对于 struct FOO
这样的聚合,做
struct FOO new_foo = { 0 };
等价于用 0 显式初始化它的每个成员,这意味着你得到正确的零值,即使那不是全位 0。最后,任何时候你声明一个具有静态持续时间的变量,如
static FOO foo_zero;
你会得到一个隐式初始化,就像你说的那样 = { 0 };
,因此默认(静态)初始化无论如何也会给你那些正确的零值。
如果您仍然对 calloc
的全位 0 保证感到好奇,可以在 question 7.31 of the C FAQ list.
为什么要复杂化?
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef struct {
int buzz;
char *bazz;
} FOO;
init_foo()
上面实际上只是 returns 在堆上创建了新的 foo。一切干净。因此,让我们这样做吧:
static inline FOO * new_foo(void)
{
return calloc(1,sizeof(FOO));
}
使用与检查:
int main (void)
{
FOO * foo = new_foo();
printf("buzz: %d, bazz: %s", foo->buzz, foo->bazz );
free(foo);
return 42;
}
Godbolt 显示新结构 FOO 很好地为空
Program returned: 42
buzz: 0, bazz: (null)