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