结构零初始化方法

Posted

技术标签:

【中文标题】结构零初始化方法【英文标题】:Struct zero initialization methods 【发布时间】:2019-04-08 06:35:42 【问题描述】:

struct datainfo info =  0 ;

struct datainfo info;
memset(&info, 0, sizeof(info));

有什么区别,哪个更好?

【问题讨论】:

从语义上讲,最终结果在所有当前运行的系统上都是相同的。 是一样的。一个是另一个的语法糖。 @alinsoar 您假设空指针由全零表示,浮点零由全零表示。 @RaymondChen:我相信在 C 语言中你可以假设空指针为 0。但在 C++ 中不能。 @Bathsheba C 不要求空指针由全位零表示。虽然空指针的写法是0,但实现应该是convert 0 to whatever the internal representation is。这是not even required that null pointers of different types have the same internal representation。 【参考方案1】:

第一个是国家英里的最佳方式,因为它保证struct 成员被初始化,因为它们将用于static 存储。 也更清晰了。

从标准的角度来看,不能保证这两种方式是等价的,尽管特定的编译器可以很好地优化第一种到第二种方式,即使它最终破坏了作为填充丢弃的内存部分。

(请注意,在 C++ 中,第二种方式的行为很可能是未定义。是的,C 不是 C++,但相当多的 C 代码确实倾向于最终被移植到 C++。)

【讨论】:

说实话,也许只是我的 C++ 程序员在说话,但我发现 0 形式更清晰。可惜 C 不接受第一种形式(没有 GNU 扩展)。 @StoryTeller:确实,我想知道为什么 C 还没有?但我远非 C 专家。也许他们有他们的理由? 希望我知道,因为这是我总是绊倒我的一件事。【参考方案2】:

实际上,这两种方法很可能产生相同的结果。可能是因为在当今的常见平台上首先被编译为对 memset 本身的调用。

从语言律师的角度来看,第一种方法将对结构的所有成员进行零初始化,但没有指定任何 padding 字节可能采用的值(在各个成员中) ,或结构)。而第二种方法会将 all 字节清零。更准确地说,不能保证全字节零模式甚至是对象的“零”值。

由于(如果知道他们的目标平台)这两者在程序员的每一个方面都几乎相同,因此您可以选择最适合您偏好的一个。

就个人而言,我更喜欢初始化而不是调用memset。因为它发生在声明时,而不是在另一个声明中,更不用说可移植性方面了。这使得不可能在两者之间意外添加导致初始化无法运行的代码(尽管这不太可能),或者以某种方式出现故障。但是有些人可能会说memset 更清晰,即使对于后来阅读它的程序员也不知道0 是如何工作的。我也不能完全无视他们的论点。

【讨论】:

【参考方案3】:

正如其他人所指出的,代码是功能等效的。 使用 x86-64 gcc 8.3 编译器

代码:

#include <string.h>
main()

    struct datainfo  int i; ;
    struct datainfo info;

    memset(&info, 0, sizeof(info));

生成程序集:

main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        lea     rax, [rbp-4]
        mov     edx, 4
        mov     esi, 0
        mov     rdi, rax
        call    memset
        mov     eax, 0
        leave
        ret

而代码:

main()

    struct datainfo  int i; ;
    struct datainfo info = 0;

编译为:

main:
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], 0
        mov     eax, 0
        pop     rbp
        ret     

在我未经训练的眼睛看来,这两个输出是 11 条指令而不是 6 条指令,因此在第二个实现中至少空间更有效。但正如其他人所指出的,零初始化方法的意图要明确得多。

【讨论】:

您是否在打开优化的情况下编译了代码?以固定的小尺寸调用memset 应该是优化器的牺牲品, @harper 没有启用编译器选项。如果您有兴趣尝试各种编译器的编译输出,可以在这里在线试用:godbolt.org

以上是关于结构零初始化方法的主要内容,如果未能解决你的问题,请参考以下文章

零初始化的结构不会出现在内存中

从零开发区块链应用--结构体初识

.NET 是不是将结构填充初始化为零?

从零开发区块链应用--结构体初识

使用 memset 将结构体数组及其成员初始化为零

结构体struct零基础搞定C语言——12