我正在读取默认情况下数组/结构的初始值,并有这个问题:
是memset(&mystruct, 0, sizeof mystruct)一样的mystruct = { 0 };?
如果不是,有什么区别?
pae*_*bal 22
与mystruct = {0}相同的memset(&mystruct,0,sizeof mystruct); ?
没有.
memset(&mystruct, 0, sizeof mystruct) ;
Run Code Online (Sandbox Code Playgroud)
...将告诉编译器调用我们期望在执行期间将mystruct中的数据设置为零的函数.
mystruct = { 0 };
Run Code Online (Sandbox Code Playgroud)
...将设置告诉编译器自己将数据设置为零,这意味着它将:
请注意,也许编译器可以将memset优化为编译时指令(比如用第二个版本替换第一个版本),但我不会依赖它,因为memset它是来自运行时库的函数,而不是某些语言内在函数(I但我不是编译器编写者/语言律师.
来自C++,我自己的观点是,你在编译时可以做的越多,编译器在编译时就知道的越多,在执行开始之前就越好:它使编译器可以优化代码和/或生成警告/错误.
在当前的情况下,使用mystruct = { 0 };符号来初始化a 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 } ;
Run Code Online (Sandbox Code Playgroud)
K-b*_*llo 11
这是一个完全迂腐的答案,但鉴于空指针的内部表示不能保证与支持初始化0的行为memset不同(memset会做错事).也就是说,我从来没有听说过一个实现这个自由,为null提供非全0位模式.
从理论上讲,这是有区别的.如果有填充,初始化器不需要初始化填充mystruct.例如:
int main(void)
{
struct mystruct {
char a;
int what;
} s = {0};
}
Run Code Online (Sandbox Code Playgroud)
可能包含:
00 xx yy zz 00 00 00 00
Run Code Online (Sandbox Code Playgroud)
其中xx yy和zz是堆栈中的未定义字节.允许编译器执行此操作.这就是说,在所有实际的术语中,我还没有遇到过那样做的编译器.大多数理智的实现将在语义上处理这种情况,如 memset.
memset(&mystruct, 0, sizeof mystruct);
Run Code Online (Sandbox Code Playgroud)
是一份声明.它可以在任何mystruct可见的时间执行,而不仅仅是在它定义的位置执行.
mystruct = { 0 };
Run Code Online (Sandbox Code Playgroud)
实际上是一个语法错误; { 0 }不是一个有效的表达.
(我假设这mystruct是一个类型的对象struct foo.)
你可能想到的是:
struct foo mystruct = { 0 };
Run Code Online (Sandbox Code Playgroud)
哪里{ 0 }是初始化器.
如果你的编译器支持它,你也可以写:
mystruct = (struct foo){ 0 };
Run Code Online (Sandbox Code Playgroud)
其中(struct foo){ 0 }是一个文字化合物.复合文字在C99中引入; 一些C编译器,特别是微软可能不支持它.(注意,(struct foo)它不是一个强制转换操作符;它看起来类似于一个,但它后面没有表达式或带括号的类型名称.它是一个独特的语法结构.)
如果您的编译器不支持复合文字,您可以通过声明一个常量来解决它:
const struct foo foo_zero = { 0 };
struct foo mystruct;
/* ... */
mystruct = foo_zero;
Run Code Online (Sandbox Code Playgroud)
这就是它们在语法和使用它们的位置上的不同之处.还存在语义差异.
该memset调用将构成mystruct所有零的表示的所有字节设置为全零.这是一个非常低级别的操作.
另一方面,初始化器:
struct foo mystruct = { 0 };
Run Code Online (Sandbox Code Playgroud)
将第一个标量子组件设置mystruct为0,并将所有其他子组件设置为将它们初始化为静态对象 - 即,设置为0.(如果有更清晰的struct foo mystruct = { };语法来执行相同的操作会很好,但是没有'吨.)
问题是,设置一些东西0不一定与将其表示设置为全零位零一样.该值0将转换为每个标量子组件的相应类型.
对于整数,该语言保证all-bits-zero是0(但不一定是唯一的表示0)的表示.设置一个整数很可能0会将其设置为全位 - 零,但可以想象它可以将其设置为其他表示形式0.在实践中,这只会在故意反常的编译器中发生.
对于指针,大多数实现将空指针表示为全位为零,但语言并不能保证这一点,并且存在使用其他表示的实际实现.(例如,使用all-bits-one之类的东西可能会使运行时更容易检测空指针解引用.)并且表示可能因不同的指针类型而不同.请参阅comp.lang.c FAQ的第5节.
类似地,对于浮点类型,大多数实现表示0.0为全位零,但语言标准不保证它.
你也许可以蒙混过关,写作代码假定的memset通话将设置所有子为零,但这样的代码是没有严格的便携式-和墨菲定律意味着,假设将在最不方便的可能的时候失败了,也许当你将代码移植一个重要的新系统.