Как рассчитать размер элемента данных в структуре? - PullRequest
2 голосов
/ 17 июня 2020

Я не могу понять, как переменная size_1 вычисляет размер имени элемента данных. Может ли кто-нибудь объяснить (((struct cheese_msgbuf*)0)->name);, что означает и делает эта строка?

#include<stdio.h>
struct cheese_msgbuf {
    long mtype;
    char name[20];
};

int main() {
    /* calculate the size of the data to send: */
    struct cheese_msgbuf mbuf;
    int size;
    int size_1;

    size = sizeof(mbuf.name);
    printf("Using just sizeof operator: %d\n", size);

    /* Or, without a declared variable: */
    size_1 = sizeof(((struct cheese_msgbuf*)0)->name);
    printf("Using pointer: %d\n", size_1);
}

Ответы [ 3 ]

3 голосов
/ 17 июня 2020

Как вы, наверное, знаете, sizeof - это оператор, который возвращает размер указанного c C символа. Требуется либо имя переменной, либо тип; если имя переменной является именем массива, она возвращает размер всего массива в байтах.

Но не существует "прямого" способа получить размер поля структуры, поэтому вот и найденный вами трюк (я должен сказать, что ваш код говорит сам за себя):

/* Or, without a declared variable: */
size_1 = sizeof(((struct cheese_msgbuf*)0)->name);
  1. Мы строим указатель на структуру, в которой определено наше поле: ((struct cheese_msgbuf*)0) . Мы просто приводим адрес 0; нам не нужно, чтобы это был действительный адрес, нам просто нужно указать компилятору интерпретировать его как указатель на (struct cheese_msgbuf*)
  2. . Мы получаем доступ к нужному полю: массиву символов name. Мы делаем это, просто обращаясь к полю так же, как мы получаем к нему доступ, когда у нас есть «настоящая» переменная, например var->name.
    В этом случае мы просто обращаемся к ((struct cheese_msgbuf*)0)->name
  3. Мы передаем его оператору sizeof: sizeof(((struct cheese_msgbuf*)0)->name). Он будет разрешен как 20
3 голосов
/ 17 июня 2020

Если бы у вас был указатель p, указывающий на struct cheese_msgbuf, вы могли бы получить размер элемента name с помощью sizeof p->name.

В этом коде такого указателя нет, поэтому он создает его путем преобразования 0 в тип struct cheese_msgbuf *. Результатом является нулевой указатель.

В выполняемом коде было бы неправильно оценивать p->name, когда p является нулевым указателем. Во многих реализациях C он генерирует исключение, и это не определено стандартом C.

Однако оператор sizeof не оценивает свой операнд в этой ситуации. Это операция времени компиляции, которая производит размер операнда на основе его типа , а не на основе какой-либо фактической оценки операнда. Поскольку номинальным типом выражения ((struct cheese_msgbuf *) 0)->name является char [20], выражение sizeof ((struct cheese_msgbuf *) 0)->name дает 20.

(Если операнд sizeof является массивом переменной длины, операнд вычисляется. В противном случае, операнд не оценивается.)

2 голосов
/ 17 июня 2020

Приведение указателя NULL

вы можете посмотреть этот фрагмент кода (из приведенного выше кода):

/* Or, without a declared variable: */
size_1 = sizeof(((struct cheese_msgbuf*)0)->name);
printf("Using pointer: %d\n", size_1);

Этот трюк известен в программировании c как приведение NULL ptr . мы можем посмотреть на null poiters, например: (void*)0, и таким же образом мы можем преобразовать их в наши собственные определенные типы, такие как ваш тип struct cheese_msgbuf.

компилятор поможет вам получить sizeof struct cheese_msgbuf элемент данных name, как показано ниже:

struct cheese_msgbuf* compiler_temp_pointer = ((struct cheese_msgbuf*)0);
size_t size = sizeof(compiler_temp_pointer->name);

надеюсь, что это проясняет для вас

...