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