Страницы

Поиск по вопросам

пятница, 8 февраля 2019 г.

Объединения (пример из сетевого программирования)

Я, видимо, не совсем понимаю, как работают union в Си, поэтому просьба прокомментировать мои вопросы по следующему небольшому коду. (Чтобы сократить код, приведу только функцию main())
int main(void) { int sockfd; socklen_t size = 2000;
union { struct sockaddr sa; char mas[2000]; }un;
sockfd = socket(AF_INET, SOCK_STREAM, 0); getsockname(sockfd, (struct sockaddr*)un.mas,&size); printf("%d

", un.sa.sa_family);
return 0; }
1) Я ведь даже не заполняю структуру struct sockaddr sa, почему printf() печатает правильный ответ?
2) Если я вместо union напишу struct, то ответ будет неправильный.
3) Если переменные не будут находиться в union или struct, то вылезает предупреждение sa.sa_family’ is used uninitialized in this function.
Помогите, пожалуйста, разобраться


Ответ

Неудобный пример. Представьте что у вас есть юнион:
typedef union { struct { int value; // 4 байта }; struct { char a; // 1 байт char b; // 1 байт char c; // 1 байт char d; // 1 байт }; } Test;
Первое поле - int - объединяет в себе последующие char поля. В этом концепция union-ов. Вот трейс:
Test test; test.value = 0; // value = { 00000000 00000000 00000000 00000000 } test.a = 1; // value = { 00000000 00000000 00000000 00000001 } test.b = 2; // value = { 00000000 00000000 00000010 00000001 } test.c = 3; // value = { 00000000 00000011 00000010 00000001 } test.d = 4; // value = { 00000100 00000011 00000010 00000001 }
Видно, что меняя одно из мелких char полей меняется и большое int поле с именем value. По сути, наш union - это int число, но, для удобства, мы разделили это число на 4 байта a,b,c,d. Можем работать как со всеми 4 байтами сразу - value, так и с каждым отдельным байтом - a,b,c,d.
В вашем случае всё аналогично. Есть struct sockaddr sa, далее, его представляют как массив из char длинной в 2000 байт.
1.) Заполняете.
getsockname(sockfd, (struct sockaddr*)un.mas,&size); // передаёте указатель на начало массива char.Данные пишутся туда, как видно из моего примера с int числом, заполняя a,b,c,d мы меняем value. Здесь так же. Заполняя массив, мы меняем sa.
2.) И это логично, структура - это структура, юнион - это юнион. Не путайте их.
3.) Неужели даже так не получается?
struct sockaddr sa; sockfd = socket(AF_INET, SOCK_STREAM, 0); getsockname(sockfd, (struct sockaddr*)&sa,&size); printf("%d

", sa.sa_family);

Комментариев нет:

Отправить комментарий