Одна проблема с подходом частичной инициализации (то есть '{ 0 }
') заключается в том, что GCC предупредит вас, что инициализатор неполон (если уровень предупреждения достаточно высок; я обычно использую '-Wall
' и часто ' -Wextra
'). С назначенным подходом инициализатора, это предупреждение не должно быть дано, но C99 все еще не широко используется - хотя эти части довольно широко доступны, за исключением, возможно, в мире Microsoft.
I склонен использовать в пользу подхода:
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()
часто является допустимой альтернативой.