Страницы

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

понедельник, 6 января 2020 г.

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

#c #объединение #сетевое_программирование


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

Помогите, пожалуйста, разобраться
    


Ответы

Ответ 1



Неудобный пример. Представьте что у вас есть юнион: 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\n\n", sa.sa_family);

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

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