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

时间:2021-06-25 19:56:21

标签: c struct initialization dynamic-memory-allocation

抱歉,如果这是重复的,在这种情况下,我找不到要搜索的正确关键字。

这是参考我正在处理的一些旧(MUD)代码,粘贴在下面。我对下面代码的 foo_zero*foo = foo_zero 部分的用途感到困惑。这是它在整个代码库中使用的模式。我的猜测是,这是一种无需显式设置即可将 foo 的所有成员初始化为零/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;
}

3 个答案:

答案 0 :(得分:2)

是的,线条

static FOO foo_zero;

*foo = foo_zero;

安排 struct FOO 分配的 init_foo() 的每个新实例都像有人说的那样初始化

struct FOO new_foo = { 0 };

具体来说,所有整数字段将初始化为 0,所有浮点字段将初始化为 0.0,所有指针字段将初始化为空指针(又名 NULL,或 nullptr in C++)。

这是一种很好的技术,因为它比其他技术更简单,而且严格来说更便于携带。

在评论中讨论了关于其他可能性的讨论

foo = malloc(sizeof(*foo));
memset(foo, 0, sizeof(*foo));

foo = calloc(1, sizeof(*foo));

这两种方法都会将全新的 struct FOO 初始化为 all-bits-0。这里有一个微妙的问题——它是如此微妙以至于许多程序员根本不会称之为问题——是处理器和/或操作系统在理论上可能表示一个浮点值 0.0 或一个 null指针,具有除 all-bits-0 以外的其他位模式。

但是如果你使用这样的处理器,那么做

float f = 0;

char *p = 0;

会做正确的事情,用正确的零值初始化变量,即使它不是全位 0。对于诸如 struct FOO 之类的聚合,执行

struct FOO new_foo = { 0 };

等价于用 0 显式初始化它的每个成员,这意味着您得到正确的零值,即使那不是全部位 0。最后,任何时候你声明一个具有静态持续时间的变量,如

static FOO foo_zero;

您会得到一个隐式初始化,就像您说 = { 0 }; 一样,因此默认(静态)初始化也无论如何都会为您提供正确的零值。

如果您仍然对 calloc 的 all-bits-0 保证感到好奇,您可以在 question 7.31C FAQ list 中阅读更多相关内容。

答案 1 :(得分:1)

其实这个声明

static FOO foo_zero;

相当于下面的

static FOO foo_zero = { .buzz = 0, .bazz = 0 };

所以在这个赋值语句中

*foo = foo_zero;

指针 foo 所指向的对象以与静态变量 foo_zero 相同的方式进行零初始化。

该函数返回一个指向零初始化对象的指针。

对于这个简单的情况,如果您使用 malloc 代替 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;
}

答案 2 :(得分:0)

为什么要复杂化?

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef struct {
    int buzz;
    char *bazz;
} FOO;
上面的

init_foo() 实际上只是返回在堆上创建的新 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)