我正在阅读默认的数组/结构的初始化值,并且有这个问题:
是memset(&mystruct, 0, sizeof mystruct)
一样的mystruct = { 0 };
吗?
如果不是,有什么区别?
memset(&mystruct, 0, sizeof mystruct) 是否与 mystruct = { 0 } 相同;?
不。
memset(&mystruct, 0, sizeof mystruct) ;
... 将告诉编译器调用我们期望在执行期间将 mystruct 中的数据设置为零的函数。
mystruct = { 0 };
...将设置告诉编译器自己将数据设置为零,这意味着它将:
请注意,也许编译器可以将 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 } ;
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.
理论上是有区别的。如果有一些 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
.
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
调用会将所有子组件设置为零的代码,但这样的代码并不是严格可移植的——墨菲定律暗示该假设将在最不方便的时刻失败,也许当您移植代码时到一个重要的新系统。