Всякий раз, когда я смотрю на реальный код или пример кода сокета в книгах, man-страницах и веб-сайтах, я почти всегда вижу что-то вроде:
struct sockaddr_in foo;
memset(&foo, 0, sizeof foo);
/* or bzero(), which POSIX marks as LEGACY, and is not in standard C */
foo.sin_port = htons(42);
вместо:
struct sockaddr_in foo = { 0 };
/* if at least one member is initialized, all others are set to
zero (as though they had static storage duration) as per
ISO/IEC 9899:1999 6.7.8 Initialization */
foo.sin_port = htons(42);
или
struct sockaddr_in foo = { .sin_port = htons(42) }; /* New in C99 */
или:
static struct sockaddr_in foo;
/* static storage duration will also behave as if
all members are explicitly assigned 0 */
foo.sin_port = htons(42);
То же самое можно найти и для установки привязки struct addrinfo к нулю, прежде чем передать его, например, в getaddrinfo.
Почему это? Насколько я понимаю, примеры, которые не используют memset, скорее всего, будут эквивалентны тем, которые делают, если не лучше. Я понимаю, что есть различия:
- memset установит все биты в ноль, что не обязательно является правильным представлением бит для установки каждого элемента в 0.
- memset также установит биты заполнения в ноль.
Являются ли какие-либо из этих различий релевантными или требуемыми поведением при установке этих структур на ноль, и поэтому использование инициализатора является неправильным? Если да, то почему, и какой стандарт или другой источник подтверждает это?
Если оба правильны, почему memset/bzero имеет тенденцию появляться вместо инициализатора? Это только вопрос стиля? Если так, то хорошо, я не думаю, что нам нужен субъективный ответ, на котором лучше стиль.
Обычная практика заключается в том, чтобы использовать инициализатор, предпочитая memset именно потому, что обычно не требуются все биты нуль, и вместо этого мы хотим получить правильное представление нуля для типа (ов). Верно ли это для этих структур, связанных со связью?
В моих исследованиях я обнаружил, что POSIX, похоже, требует, чтобы sockaddr_in6 (а не sockaddr_in) был обнулен в http://www.opengroup.org/onlinepubs/000095399/basedefs/netinet/in.h.html, но не упоминает как он должен быть обнулен (memset или initializer?). Я понимаю, что BSD-сокеты предшествуют POSIX, и это не единственный стандарт, так же как их соображения совместимости для устаревших систем или современных не-POSIX-систем?
Лично я предпочитаю использовать стиль (и, возможно, хорошую практику) для использования инициализатора и полностью избегать memset, но я неохотно, потому что:
- Другие исходные тексты и полуканонические тексты, такие как Сетевое программирование UNIX, используют bzero (например, стр. 101 на 2-е изд. и стр. 124 в 3-й (у меня есть оба)).
- Мне хорошо известно, что они не идентичны по причинам, указанным выше.