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

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

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

如果不是,有什么区别?

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

没有。

 memset(&mystruct, 0, sizeof mystruct) ; 

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

 mystruct = { 0 }; 

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

  • 如果可能的话在编译时将 mystruct中的数据设置为零(例如,对于静态变量,如tristopia和Oli Charlesworth在评论中所述)
  • 或者如果不是 (例如自动变量),生成汇编代码,在初始化变量时将数据设置为零(这比调用函数更好)。

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

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

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

以下示例显示代码很容易执行与其显示不同的操作:

 // 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 } ; 

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

从理论上讲,这是有区别的。 如果mystruct有一些,则初始化者不需要初始化填充。 例如:

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

可能包含:

 00 xx yy zz 00 00 00 00 

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

 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第一个mystruct组件mystruct为0,并将所有其他子组件设置为将它们初始化为静态对象 – 即,设置为0.(如果有一个更清晰的struct foo mystruct = { };会很好struct foo mystruct = { };语法要做同样的事情,但没有。)

问题是,将某事物设置为0并不一定与将其表示设置为全部位零相同。 值0转换为每个标量子组件的相应类型。

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

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

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

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