为什么编码器将结构指针的值分配给静态结构?

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)