部分初始化方法(即 ' { 0 }
')的一个问题是 GCC 会警告您初始化程序不完整(如果警告级别足够高;我通常使用 ' -Wall
' 并且经常使用 ' -Wextra
')。使用指定的初始化方法,不应该给出警告,但 C99 仍然没有被广泛使用——尽管这些部分相当广泛可用,也许在 Microsoft 的世界中除外。
我倾向于使用一种方法:
static const struct sockaddr_in zero_sockaddr_in;
其次是:
struct sockaddr_in foo = zero_sockaddr_in;
静态常量中初始化器的省略意味着一切都为零 - 但编译器不会机智(不应该机智)。分配使用编译器的固有内存副本,除非编译器严重不足,否则它不会比函数调用慢。
GCC 随着时间的推移发生了变化
GCC 版本 4.4.2 到 4.6.0 生成与 GCC 4.7.1 不同的警告。具体来说,GCC 4.7.1 将= { 0 }
初始化程序识别为“特殊情况”并且不会抱怨,而 GCC 4.6.0 等确实会抱怨。
考虑文件init.c
:
struct xyz
{
int x;
int y;
int z;
};
struct xyz xyz0; // No explicit initializer; no warning
struct xyz xyz1 = { 0 }; // Shorthand, recognized by 4.7.1 but not 4.6.0
struct xyz xyz2 = { 0, 0 }; // Missing an initializer; always a warning
struct xyz xyz3 = { 0, 0, 0 }; // Fully initialized; no warning
使用 GCC 4.4.2(在 Mac OS X 上)编译时,警告如下:
$ /usr/gcc/v4.4.2/bin/gcc -O3 -g -std=c99 -Wall -Wextra -c init.c
init.c:9: warning: missing initializer
init.c:9: warning: (near initialization for ‘xyz1.y’)
init.c:10: warning: missing initializer
init.c:10: warning: (near initialization for ‘xyz2.z’)
$
使用 GCC 4.5.1 编译时,警告是:
$ /usr/gcc/v4.5.1/bin/gcc -O3 -g -std=c99 -Wall -Wextra -c init.c
init.c:9:8: warning: missing initializer
init.c:9:8: warning: (near initialization for ‘xyz1.y’)
init.c:10:8: warning: missing initializer
init.c:10:8: warning: (near initialization for ‘xyz2.z’)
$
使用 GCC 4.6.0 编译时,警告是:
$ /usr/gcc/v4.6.0/bin/gcc -O3 -g -std=c99 -Wall -Wextra -c init.c
init.c:9:8: warning: missing initializer [-Wmissing-field-initializers]
init.c:9:8: warning: (near initialization for ‘xyz1.y’) [-Wmissing-field-initializers]
init.c:10:8: warning: missing initializer [-Wmissing-field-initializers]
init.c:10:8: warning: (near initialization for ‘xyz2.z’) [-Wmissing-field-initializers]
$
使用 GCC 4.7.1 编译时,警告是:
$ /usr/gcc/v4.7.1/bin/gcc -O3 -g -std=c99 -Wall -Wextra -c init.c
init.c:10:8: warning: missing initializer [-Wmissing-field-initializers]
init.c:10:8: warning: (near initialization for ‘xyz2.z’) [-Wmissing-field-initializers]
$
上面的编译器是我编译的。Apple 提供的编译器名义上是 GCC 4.2.1 和 Clang:
$ /usr/bin/clang -O3 -g -std=c99 -Wall -Wextra -c init.c
init.c:9:23: warning: missing field 'y' initializer [-Wmissing-field-initializers]
struct xyz xyz1 = { 0 };
^
init.c:10:26: warning: missing field 'z' initializer [-Wmissing-field-initializers]
struct xyz xyz2 = { 0, 0 };
^
2 warnings generated.
$ clang --version
Apple clang version 4.1 (tags/Apple/clang-421.11.65) (based on LLVM 3.1svn)
Target: x86_64-apple-darwin11.4.2
Thread model: posix
$ /usr/bin/gcc -O3 -g -std=c99 -Wall -Wextra -c init.c
init.c:9: warning: missing initializer
init.c:9: warning: (near initialization for ‘xyz1.y’)
init.c:10: warning: missing initializer
init.c:10: warning: (near initialization for ‘xyz2.z’)
$ /usr/bin/gcc --version
i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)
Copyright (C) 2007 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$
正如SecurityMatt在下面的评论中所指出的,memset()
从内存中复制结构的优势在于从内存中复制的成本更高,需要访问两个内存位置(源和目标)而不仅仅是一个。相比之下,将值设置为零不必访问内存以获取源代码,并且在现代系统上,内存是一个瓶颈。因此,memset()
对于简单的初始化程序,编码应该比复制更快(相同的值,通常都是零字节,被放置在目标内存中)。如果初始值设定项是值的复杂组合(并非全为零字节),那么平衡可能会更改为有利于初始值设定项,以保证符号的紧凑性和可靠性(如果没有别的)。
没有一个简单的答案......可能从来没有,现在也没有。我仍然倾向于使用初始化器,但memset()
通常是一个有效的替代方案。