部分初始化方法(即“{ 0 }”)的一个问题是 GCC 会警告您初始化程序不完整(如果警告级别足够高;我通常使用“-Wall”并且经常使用“ -Wextra')。使用指定的初始化方法,不应该给出警告,但 C99 仍然没有被广泛使用 - 尽管这些部分相当广泛,除了微软的世界。
我倾向于曾经倾向于一种方法:
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() 通常是一个有效的替代方案。