21

我正在阅读默认的数组/结构的初始化值,并且有这个问题:

memset(&mystruct, 0, sizeof mystruct)一样的mystruct = { 0 };吗?

如果不是,有什么区别?

4

4 回答 4

23

memset(&mystruct, 0, sizeof mystruct) 是否与 mystruct = { 0 } 相同;?

不。

memset(&mystruct, 0, sizeof mystruct) ;

... 将告诉编译器调用我们期望在执行期间将 mystruct 中的数据设置为零的函数。

mystruct = { 0 };

...将设置告诉编译器自己将数据设置为零,这意味着它将:

  • 如果可能,在编译时将 mystruct 中的数据设置为零(例如对于静态变量,正如tristopiaOli Charlesworth在评论中所说)
  • 或者如果不是(例如自动变量),则生成汇编代码,该代码将在变量初始化时将数据设置为零(这比调用函数执行此操作要好)。

请注意,也许编译器可以将 memset 优化为编译时指令(例如用第二个版本替换第一个版本memset),但我不会像运行时库中的函数那样依赖它,而不是某些语言内在(我不过,我不是编译器作家/语言律师)。

来自 C++,我自己的观点是,你在编译时可以做的越多,编译器在编译时知道的越多,甚至在执行开始之前就越好:它使编译器能够优化代码和/或生成警告/错误。

在当前情况下,使用mystruct = { 0 };符号来初始化 astruct总是比使用 memset 更安全,因为在 C 中用 a 编写错误的东西非常memset容易,而编译器不会抱怨。

以下示例表明,代码很容易做一些与看起来不同的事情:

// only the 1st byte will be set to 0
memset(&mystruct, 0, sizeof(char)) ;          

// will probably overrun the data, possibly corrupting
// the data around it, and you hope, crashing the process.
memset(&mystruct, 0, sizeof(myLARGEstruct)) ; 

// will NOT set the data to 257. Instead it will truncate the
// integer and set each byte to 1
memset(&mystruct, 257, sizeof(mystruct)) ;    

// will set each byte to the value of sizeof(mystruct) modulo 256
memset(&mystruct, sizeof(mystruct), 0) ;      

// will work. Always.
mystruct = { 0 } ;
于 2012-05-28T18:18:58.530 回答
11

This is a completely pedantic answer, but given that the internal representation of a null pointer is not guaranted to be 0 the behavior of memset versus brace-initialization would differ (memset would do the wrong thing). That said, I've never heard of an implementation that took on this liberty to have a non all 0 bit pattern for null.

于 2012-05-28T18:42:50.400 回答
9

理论上是有区别的。如果有一些 in ,则初始化程序不需要初始化填充mystruct。例如:

int main(void) 
{
     struct mystruct {
          char    a;
          int     what;
     } s = {0};
}

可能包含:

00 xx yy zz 00 00 00 00

其中 xx yy 和 zz 是堆栈中的未定义字节。允许编译器这样做。这就是说,实际上,我还没有遇到过这样做的编译器。大多数理智的实现将在语义上处理这种情况,例如 memset.

于 2012-05-28T18:42:26.097 回答
8
memset(&mystruct, 0, sizeof mystruct);

是一个声明。它可以在mystruct可见的任何时间执行,而不仅仅是在它被定义的地方。

mystruct = { 0 };

实际上是语法错误;{ 0 }不是一个有效的表达式。

(我假设这mystruct是一个类型的对象struct foo。)

你可能想到的是:

struct foo mystruct = { 0 };

{ 0 }初始化器在哪里。

如果您的编译器支持它,您还可以编写:

mystruct = (struct foo){ 0 };

其中(struct foo){ 0 }复合文字。C99 中引入了复合文字;一些 C 编译器,尤其是微软的可能不支持它。(请注意,这不是(struct foo)强制转换运算符;它看起来与 one 相似,但后面没有表达式或带括号的类型名称。它是一种独特的语法结构。)

如果您的编译器不支持复合文字,您可以通过声明一个常量来解决它:

const struct foo foo_zero = { 0 };

struct foo mystruct;
/* ... */
mystruct = foo_zero;

这就是它们在语法和使用位置上的不同之处。还有语义上的差异。

memset调用将构成 of 表示的所有字节设置mystruct为全零。这是一个非常低级的操作。

另一方面,初始化器:

struct foo mystruct = { 0 };

将第一个标量子组件设置mystruct为 0,并将所有其他子组件设置为好像它们被初始化为静态对象 - 即,设置为 0。(如果有更简洁的struct foo mystruct = { };语法来做同样的事情,那就太好了,但是没有'吨。)

问题是,将某些内容设置0为不一定与将其表示设置为全零位相同。该值0转换为每个标量子组件的适当类型。

对于整数,该语言保证所有位为零是 的表示0(但不一定是 的唯一表示0)。将整数设置为 很可能0会将其设置为所有位为零,但可以想象它可以将其设置为0. 在实践中,这只会发生在故意不正当的编译器上。

对于指针,大多数实现将空指针表示为所有位为零,但语言不保证这一点,并且存在使用其他表示的实际实现。(例如,使用像 all-bits-one 这样的东西可能会使空指针取消引用在运行时更容易检测到。)并且对于不同的指针类型,表示可能会有所不同。请参阅comp.lang.c FAQ的第 5 节。

同样,对于浮点类型,大多数实现都表示0.0为全零,但语言标准不保证这一点。

您可能可以编写假设memset调用会将所有子组件设置为零的代码,但这样的代码并不是严格可移植的——墨菲定律暗示该假设将在最不方便的时刻失败,也许当您移植代码时到一个重要的新系统。

于 2012-05-28T21:25:02.250 回答