将对象初始化为全零

das*_*ang 18 c c++ struct

通常,数据结构的有效初始化是将所有成员设置为零.即使使用C++进行编程,也可能需要与外部API进行交互.

以下是否有任何实际区别:

some_struct s;
memset(&s, 0, sizeof(s));
Run Code Online (Sandbox Code Playgroud)

简单地说

some_struct s = { 0 };
Run Code Online (Sandbox Code Playgroud)

人们发现自己都使用这两种方法,选择哪种方法更适合给定的应用程序?(希望据了解,这只适用于POD结构;如果该结构中存在C++ std :: string,则会遇到各种各样的破坏.)

对于我自己来说,作为一个不使用memset的C++程序员,我从不确定函数签名,所以我发现第二个例子更容易使用,除了更少打字,更紧凑,甚至更多很明显,因为它在声明中说"这个对象被初始化为零"而不是等待下一行代码并且看到"哦,这个对象初始化为零".

在C++中创建类和结构时,我倾向于使用初始化列表; 我很好奇人们对上面两个"C风格"初始化的想法,而不是与C++中可用的内容进行比较,因为我怀疑我们很多人都与C库接口,即使我们自己主要用C++编写代码.

编辑: Neil Butterworth 在后续提出这个问题,我认为这是这个问题的一个有趣的推论.

AnT*_*AnT 23

memset实际上从来都不是正确的方法.是的,存在实际差异(见下文).

在C++中,不是所有东西都可以用文字初始化0(枚举类型的对象不能),这就是为什么在C++中常见的习语是

some_struct s = {};
Run Code Online (Sandbox Code Playgroud)

而在C语言中,成语是

some_struct s = { 0 };
Run Code Online (Sandbox Code Playgroud)

注意,在C = { 0 }中,可以称为 通用零初始化器.它可以与几乎任何类型的对象一起使用,因为{}-enclosed初始化器也允许使用标量对象

int x = { 0 }; /* legal in C (and in C++) */
Run Code Online (Sandbox Code Playgroud)

这使得= { 0 }在通用类型无关的C代码(例如,与类型无关的宏)中有用.

= { 0 }C89/90和C++ 中初始化程序的缺点是它只能用作声明的一部分.(C99通过引入固定这个问题复合文字.类似的功能即将C++为好.)由于这个原因,你可能会看到许多程序员使用memset以零出来的东西在C89/90或C++代码的中间.然而,我会说正确的做法仍然没有memset,而是有类似的东西

some_struct s;
...
{
  const some_struct ZERO = { 0 };  
  s = ZERO;
}
...
Run Code Online (Sandbox Code Playgroud)

即通过在代码中间引入"虚构"块,即使它在第一眼看上去看起来不太漂亮.当然,在C++中没有必要引入块.

至于实际差异......你可能会听到有些人说memset在实践中会产生相同的结果,因为实际上物理的全零位模式是用来表示所有类型的零值.但是,这通常不是真的.一个能够证明典型C++实现差异的直接示例是指向数据成员的指针类型

struct S;
...

int S::*p = { 0 };
assert(p == NULL); // this assertion is guaranteed to hold

memset(&p, 0, sizeof p);
assert(p == NULL); // this assertion will normally fail
Run Code Online (Sandbox Code Playgroud)

发生这种情况是因为典型的实现通常使用全一位模式(0xFFFF...)来表示此类型的空指针.上面的例子演示了归零memset和普通= { 0 }初始化器之间的实际实际差异.

  • @AndreyT:`"当然,在C++中没有必要引入一个块",为什么?另外,为什么要在C中引入块? (2认同)

Mar*_*som 15

some_struct s = { 0 };保证工作; memset依赖于实施细节,最好避免.

  • 如果这是关于C++,那么不,当`some_struct`的第一个成员是枚举对象时,它将*不工作.这是在C++中引入`= {}`初始值设定项的原因之一. (4认同)

Ark*_*kku 6

如果struct包含指针,则所产生的所有位0的值memset可能与0在C(或C++)代码中指定它的意义不同,即NULL指针.

(这也可能是与案件floatsdoubles,但是,我从来没有遇到过.不过,我不认为标准保证了他们能够成为零memset无论是.)

编辑:从一个更务实的角度来看,我仍然会说memset尽可能避免使用,因为它是一个额外的函数调用,写入时间更长,并且(在我看来)意图不太明确= { 0 }.

  • @Rob Kennedy:嗯,有些机器对空指针的表示非零,所以这些机器上的实际差异很大.当然,我们可能会认为这些机器不切实际.=) (5认同)
  • @Rob Kennedy:不正确.指针到数据成员,例如`int S ::*p`通常*从不*对零指针使用全零位模式.它们使用全一位模式(0xFFF ...),这是一个*实用的例子,当你不能获得带有`memset(...,0,...)`的空指针时.有趣的是,我们的日常机器和实现就是这种情况:G ++,MSVC++.它一直生活在我们的鼻子底下.没什么异国情调的. (4认同)
  • C和C++标准不要求所有的零位都变为0.0作为浮点数,但IEEE标准可以.有些机器不遵循IEEE标准,但我知道它们都将所有位零转换为0.0. (2认同)

dra*_*ard 5

根据编译器优化,可能存在一些阈值,高于该阈值,memset更快,但通常远高于基于堆栈的变量的正常大小.在带有虚拟表的C++对象上使用memset当然很糟糕.