我正在读取默认情况下数组/结构的初始值,并有这个问题:
memset(&mystruct, 0, sizeof mystruct)
与mystruct = { 0 };
相同?
如果不是,有什么区别?
答案 0 :(得分:22)
是与mystruct = {0}相同的memset(& mystruct,0,sizeof mystruct); ?
没有
memset(&mystruct, 0, sizeof mystruct) ;
...将告诉编译器调用一个函数,我们期望在执行期间 将mystruct中的数据设置为零。
mystruct = { 0 };
...将设置告诉编译器自己将数据设置为零,这意味着它将:
注意或许编译器可以将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)
这是一个完全迂腐的答案,但鉴于空指针的内部表示不能保证为0
,memset
与大括号初始化的行为会有所不同(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 }
不是有效的表达。
(我假设mystruct
是struct 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意味着假设在最不方便的时刻失败,也许当你将代码移植到一个重要的新系统时。