Я, видимо, не совсем понимаю, как работают 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);