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

memset(&;mystruct,0,mystruct的大小)与mystruct={0};相同吗;?,c,struct,C,Struct,我正在阅读有关默认情况下数组/结构的初始化值的信息,并有以下问题: 是memset(&mystruct,0,mystruct的大小)与mystruct={0}相同 如果不是,有什么区别 memset(&mystruct,0,mystruct的大小)与mystruct={0};相同吗 没有 。。。将告诉编译器调用我们期望在执行期间将mystruct中的数据设置为零的函数 mystruct = { 0 }; 。。。将告诉编译器自己将数据设置为零,这意味着它将: 如果可能,在编译时将mystruc

我正在阅读有关默认情况下数组/结构的初始化值的信息,并有以下问题:

memset(&mystruct,0,mystruct的大小)
mystruct={0}相同

如果不是,有什么区别

memset(&mystruct,0,mystruct的大小)与mystruct={0};相同吗

没有

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

mystruct = { 0 };
。。。将告诉编译器自己将数据设置为零,这意味着它将:

  • 如果可能,在编译时将mystruct中的数据设置为零(例如,对于静态变量,如注释中所述)
  • 或者,如果没有(例如自动变量),则生成汇编代码,在初始化变量时将数据设置为零(这比调用函数更好)
请注意,也许编译器可以将memset优化为编译时指令(比如用第二个版本替换第一个版本),但我不相信这一点,因为
memset
是运行库中的一个函数,而不是某种固有的语言(尽管我不是编译器编写者/语言律师)

<>从C++中,我自己的观点是,编译时你能做的越多,编译器在编译时知道的越多,在执行甚至启动之前,它就越好:编译器可以优化代码和/或生成警告/错误。 在当前情况下,使用
mystruct={0}表示法初始化
结构总是比使用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 } ;

理论上是有区别的。如果
mystruct
中存在填充,则不需要初始化器初始化填充。 例如:

int main(void) 
{
     struct mystruct {
          char    a;
          int     what;
     } s = {0};
}
可能包含:

00 xx yy zz 00 00 00 00
其中xx yy和zz是堆栈上where的未定义字节。 编译器可以这样做。
也就是说,从实用的角度来看,我还没有遇到过这样的编译器。大多数理智的实现都会像
memset

那样在语义上处理这种情况,这是一个完全迂腐的答案,但鉴于空指针的内部表示形式不能保证为
0
memset
与括号初始化的行为会有所不同(
memset
会做错误的事情)。也就是说,我从来没有听说过有一个实现可以如此自由地将非全0位模式用于null

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编译器,特别是Microsoft的可能不支持它。(注意,
(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
与将其表示形式设置为所有位零并不一定是一回事。值
0
被转换为每个标量子组件的适当类型

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

对于指针,大多数实现都将空指针表示为所有位零,但该语言不能保证这一点,而且现实世界中也有一些实现使用其他表示形式(例如,使用类似于所有位的内容可能会使空指针解引用在运行时更容易检测)对于不同的指针类型,表示形式可能会有所不同。请参阅本手册第5节

类似地,对于浮点类型,大多数实现将
0.0
表示为所有位为零,但语言标准并不保证这一点


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

@awoodland:是吗?那么是哪一个不需要参数的
sizeof
变体?@awoodland:
sizeofstruct foo mystruct = { 0 };