Как я могу использовать "размер" в макрос?


есть ли способ, чтобы использовать sizeof в макрос?

например, за эти годы было много ситуаций, в которых я хотел сделать что-то вроде:

#if sizeof(someThing) != PAGE_SIZE
#error Data structure doesn't match page size
#endif

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

Излишне говорить - Я, кажется, не в состоянии использовать sizeof описанным выше способом.

11 72

11 ответов:

есть ли в любом случае использовать "sizeof" в препроцессор макрос?

нет. Условные директивы принимают ограниченный набор условных выражений;sizeof одна из вещей не допускается.

директивы предварительной обработки вычисляются до того, как источник будет проанализирован (по крайней мере, концептуально), поэтому еще нет никаких типов или переменных, чтобы получить их размер.

однако существуют методы получения утверждений времени компиляции в C (для пример см. на этой странице).

есть несколько способов сделать это. Следующие фрагменты кода не будут производить код, если sizeof(someThing) равна PAGE_SIZE; в противном случае они будут производить Ошибка времени компиляции.

1. С11 способом

начиная с C11 вы можете использовать static_assert.

использование:

static_assert(sizeof(someThing) == PAGE_SIZE, "Data structure doesn't match page size");

2. Пользовательский макрос

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

#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))

использование:

BUILD_BUG_ON( sizeof(someThing) != PAGE_SIZE );

в этой статье подробно объясняет, почему это работает.

3. МС-специфический

на компиляторе Microsoft C++ вы можете использовать C_ASSERT макрос (требуется #include <windows.h>), которая использует трюк, подобный описанному в разделе 2.

использование:

C_ASSERT(sizeof(someThing) == PAGE_SIZE);

Я знаю, что этот поток очень старых, но...

мое решение:

extern char __CHECK__[1/!(<<EXPRESSION THAT SHOULD COME TO ZERO>>)];

пока это выражение равно нулю, оно компилируется нормально. Что-нибудь еще, и он взорвется прямо там. Поскольку переменная extern'D, она не займет места, и пока никто не ссылается на нее (чего они не будут), это не вызовет ошибку ссылки.

Не так гибко, как макрос assert, но я не мог заставить его компилироваться в моей версии GCC, и это будет... и я думаю, что это будет компилироваться практически в любом месте.

Я знаю, что это поздний ответ, но чтобы добавить к версии Майка, вот версия, которую мы используем, которая не выделяет никакой памяти. Я не придумал оригинальную проверку размера, я нашел ее в интернете много лет назад и, к сожалению, не могу ссылаться на автора. Два других являются просто продолжением одной и той же идеи.

потому что они typedef, ничего не выделяется. С _ _ LINE__ в имени, это всегда другое имя, так что его можно скопировать и вставить, где это необходимо. Это работает в MS Компиляторы Visual Studio C и компиляторы GCC Arm. Он не работает в CodeWarrior, CW жалуется на переопределение,не используя конструкцию препроцессора__ LINE__.

//Check overall structure size
typedef char p__LINE__[ (sizeof(PARS) == 4184) ? 1 : -1];

//check 8 byte alignment for flash write or similar
typedef char p__LINE__[ ((sizeof(PARS) % 8) == 0) ? 1 : 1];

//check offset in structure to ensure a piece didn't move
typedef char p__LINE__[ (offsetof(PARS, SUB_PARS) == 912) ? 1 : -1];

Как насчет следующего макроса:

/* 
 * Simple compile time assertion.
 * Example: CT_ASSERT(sizeof foo <= 16, foo_can_not_exceed_16_bytes);
 */
#define CT_ASSERT(exp, message_identifier) \
    struct compile_time_assertion { \
        char message_identifier : 8 + !(exp); \
    }

например в комментарии MSVC говорит что-то вроде:

test.c(42) : error C2034: 'foo_can_not_exceed_16_bytes' : type of bit field too small for number of bits

Так же, как ссылка для этого обсуждения, я сообщаю, что некоторые компиляторы получают sizeof() AR pre-processor time.

JamesMcNellis ответ правильный, но некоторые компиляторы проходят через это ограничение (это, вероятно, нарушает строгий ansi c).

в этом случае я ссылаюсь на IAR C-compiler (вероятно, ведущий для профессионального микроконтроллера/встроенного программирования).

#define SIZEOF(x) ((char*)(&(x) + 1) - (char*)&(x)) может работать

существующие ответы просто показывают, как достичь эффекта "утверждений времени компиляции" на основе размера типа. Это может удовлетворить потребности OP в данном конкретном случае, но есть и другие случаи, когда вам действительно нужен препроцессор, обусловленный размером типа. Вот как это сделать:

напишите себе небольшую программу на C, например:

/* you could call this sizeof_int.c if you like... */
#include <stdio.h>
/* 'int' is just an example, it could be any other type */
int main(void) { printf("%zd", sizeof(int); }

компиляции, что. Напишите сценарий на вашем любимом языке сценариев, который запускает вышеуказанную программу C и захватывает свой выход. Используйте этот вывод для создания файла заголовка C. Например, если вы используете Ruby, это может выглядеть так:

sizeof_int = `./sizeof_int`
File.open('include/sizes.h','w') { |f| f.write(<<HEADER) }
/* COMPUTER-GENERATED, DO NOT EDIT BY HAND! */
#define SIZEOF_INT #{sizeof_int}
/* others can go here... */
HEADER

затем добавьте правило в свой Makefile или другой скрипт сборки, который заставит его запустить вышеупомянутый скрипт для сборки sizes.h.

включить sizes.h везде, где вам нужно использовать препроцессорные условные обозначения на основе размеров.

готово!

(вы когда-нибудь наберется ./configure && make построить программу? Что configure скрипты делают в основном так же, как выше...)

в моем портативном коде c++ (http://www.starmessagesoftware.com/cpcclibrary/) хотел поставить надежную защиту на размеры некоторых из моих структур или классов.

вместо того, чтобы найти способ для препроцессора выдать ошибку ( которая не может работать с sizeof (), как указано здесь), я нашел здесь решение, которое заставляет компилятор выдавать ошибку. http://www.barrgroup.com/Embedded-Systems/How-To/C-Fixed-Width-Integers-C99

У меня был чтобы адаптировать этот код, чтобы он вызывал ошибку в моем компиляторе (xcode):

static union
{
    char   int8_t_incorrect[sizeof(  int8_t) == 1 ? 1: -1];
    char  uint8_t_incorrect[sizeof( uint8_t) == 1 ? 1: -1];
    char  int16_t_incorrect[sizeof( int16_t) == 2 ? 1: -1];
    char uint16_t_incorrect[sizeof(uint16_t) == 2 ? 1: -1];
    char  int32_t_incorrect[sizeof( int32_t) == 4 ? 1: -1];
    char uint32_t_incorrect[sizeof(uint32_t) == 4 ? 1: -1];
};

В C11 ключевое слово. Он может быть использован как:

_Static_assert(sizeof(someThing) == PAGE_SIZE, "Data structure doesn't match page size")

The sizeof оператор недоступен для препроцессора, но вы можете передать sizeof к компилятору и проверить условие во время выполнения:

#define elem_t double

#define compiler_size(x) sizeof(x)

elem_t n;
if (compiler_size(elem_t) == sizeof(int)) {
    printf("%d",(int)n);
} else {
    printf("%lf",(double)n);
}