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

时间:2012-05-28 18:17:12

标签: c struct

我正在读取默认情况下数组/结构的初始值,并有这个问题:

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

如果不是,有什么区别?

4 个答案:

答案 0 :(得分:22)

  

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

没有

memset(&mystruct, 0, sizeof mystruct) ;

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

mystruct = { 0 };

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

  • 如果可能,将mystruct中的数据设置为零编译(例如,对于静态变量,如tristopiaOli Charlesworth中标注的评论)
  • 如果不是(例如自动变量),生成汇编代码,在初始化变量时将数据设置为零(这比调用函数更好)。 / LI>

注意或许编译器可以将memset优化为编译时指令(就像用第二个版本替换第一个版本),但我不会依赖因为memset是来自运行时库的函数,而不是某些内在的语言(我不是编译器编写者/语言律师,但是)。

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

在当前的情况下,使用mystruct = { 0 };表示法来初始化struct总是比使用memset更安全,因为它非常非常很容易在C中写错了在没有编译器抱怨的情况下使用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 } ;

答案 1 :(得分:11)

这是一个完全迂腐的答案,但鉴于空指针的内部表示不能保证为0memset与大括号初始化的行为会有所不同(memset会做错事)。也就是说,我从来没有听说过一个实现这个自由,为null提供非全0位模式。

答案 2 :(得分:9)

理论上存在差异。如果mystruct中有一些填充,则初始化不需要初始化填充。 例如:

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

可能包含:

00 xx yy zz 00 00 00 00

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

答案 3 :(得分:8)

memset(&mystruct, 0, sizeof mystruct);

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

mystruct = { 0 };

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

(我假设mystructstruct foo类型的对象。)

你可能想到的是:

struct foo mystruct = { 0 };

其中{ 0 }是初始化程序。

如果你的编译器支持它,你也可以写:

mystruct = (struct foo){ 0 };

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

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

const struct foo foo_zero = { 0 };

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

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

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

另一方面,初始化程序:

struct foo mystruct = { 0 };

标量子组件mystruct设置为0,并将所有其他子组件设置为初始化为静态对象 - 即为0。有一个更清晰的struct foo mystruct = { };语法来做同样的事情,但没有。)

问题是,将某些内容设置为0并不一定与将其表示设置为all-bits-zero相同。值0 转换为每个标量子组件的相应类型。

对于整数,该语言保证all-bits-zero是0的表示(但不一定是0的唯一表示)。将整数设置为0很可能会将其设置为全位 - 零,但可以想象它可以将其设置为0的其他表示形式。在实践中,这只会在故意反复编译的情况下发生。

对于指针,大多数实现将空指针表示为全位为零,但语言并不能保证这一点,并且已经存在使用其他表示形式的实际实现。 (例如,使用all-bits-one之类的东西可能会使运行时更容易检测空指针解引用。)并且表示可能因不同的指针类型而不同。请参阅comp.lang.c FAQ的第5部分。

类似地,对于浮点类型,大多数实现将0.0表示为全位零,但语言标准不保证它。

您可能可以通过编写假设的代码 memset调用将所有子组件设置为零,但这样的代码不是严格可移植的 - 而且Murphy's Law意味着假设在最不方便的时刻失败,也许当你将代码移植到一个重要的新系统时。