sizeof abuse: получить размер таблицы const - PullRequest
1 голос
/ 26 марта 2010

При объявлении таблицы const можно получить размер таблицы с помощью sizeof. Тем не мение, как только вы перестанете использовать имя символа, оно больше не будет работать. есть ли способ заставить следующую программу вывести правильный размер для таблицы A вместо 0?

#include <stdio.h>

struct mystruct {
    int a;
    short b;
};

const struct mystruct tableA[] ={
    { 
        .a = 1,
        .b = 2,
    },
    { 
        .a = 2,
        .b = 2,
    },
    { 
        .a = 3,
        .b = 2,
    },
};

const struct mystruct tableB[] ={
    { 
        .a = 1,
        .b = 2,
    },
    { 
        .a = 2,
        .b = 2,
    },
};


int main(int argc, char * argv[]) {
    int tbl_sz;
    const struct mystruct * table;

    table = tableA;
    tbl_sz = sizeof(table)/sizeof(struct mystruct);
    printf("size of table A : %d\n", tbl_sz);

    table = tableB;
    tbl_sz = sizeof(tableB)/sizeof(struct mystruct);
    printf("size of table B : %d\n", tbl_sz);

    return 0;
}

Вывод:

size of table A : 0
size of table B : 2

Это предполагаемое поведение sizeof. Но есть ли способ для компилятора узнать размер таблицы констант, учитывая указатель на таблицу вместо имени символа?

Ответы [ 5 ]

5 голосов
/ 26 марта 2010

вы запрашиваете размер указателя. Это всегда размер указателя (т.е. обычно 4 байта на 32-битной машине и 8 байтов на 64-битной машине). Во второй попытке вы запрашиваете размер массива и, следовательно, получаете ожидаемый результат.

2 голосов
/ 26 марта 2010

Есть ли способ для компилятора узнать размер таблицы констант, учитывая указатель на таблицу вместо имени символа?

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

Итак, как все умело указали, когда вы берете размер указателя, вы получаете размер указателя. Предполагая, что стандартный 32-битный компьютер, поскольку результаты соответствуют этому предположению, ваша структура составляет 8 байтов, а ваши указатели - 4 байта, поэтому результат деления равен нулю, как и ожидалось.

1 голос
/ 26 марта 2010

Короткий ответ - нет; если все, что у вас есть, это указатель, то нет (стандартного) способа получить размер объекта, на который указывает указатель.

1 голос
/ 26 марта 2010

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

#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))

См. Этот SO-ответ для более подробной информации: Существует ли стандартная функция в C, которая возвращает длину массива?

Для еще более безопасного решения при использовании C ++ вместо C см. Этот ответ SO, в котором используются шаблоны, чтобы гарантировать, что попытка получить количество массивов по указателю всегда приведет к ошибке: Время компиляции sizeof_array без использования макроса

0 голосов
/ 26 марта 2010

Хотя синтаксически правильно, ваш образец более условно записывается как:

const struct mystruct tableA[] = {
    {1, 2},
    {2, 2},
    {3, 3}, 
};

Что является менее многословным и, следовательно, более читабельным.

...