Есть ли способ использовать a sizeof
в макросе препроцессора?
Например, за эти годы было множество ситуаций, в которых я хотел сделать что-то вроде:
#if sizeof(someThing) != PAGE_SIZE
#error Data structure doesn't match page size
#endif
То, что я здесь проверяю, полностью выдумано - дело в том, что я часто люблю вставлять эти типы (размер или выравнивание) проверок времени компиляции, чтобы защититься от того, кто-то изменит структуру данных, которая может смещаться или повторно размер вещей, которые могут их сломать.
Излишне говорить - похоже, что я не могу использовать a sizeof
описанным выше способом.
Ответы:
Есть несколько способов сделать это. Следующие ниже фрагменты кода не будут создавать кода, если они
sizeof(someThing)
равныPAGE_SIZE
; в противном случае они вызовут ошибку времени компиляции.1. Способ C11
Начиная с C11 можно использовать
static_assert
(требуется#include <assert.h>
).Использование:
2. Пользовательский макрос
Если вы просто хотите получить ошибку времени компиляции, когда
sizeof(something)
это не то, чего вы ожидаете, вы можете использовать следующий макрос:Использование:
В этой статье подробно объясняется, почему это работает.
3. Специфичные для MS
В компиляторе Microsoft C ++ вы можете использовать макрос C_ASSERT (требуется
#include <windows.h>
), который использует прием, аналогичный тому, который описан в разделе 2.Использование:
источник
gcc
(проверено на версии 4.8.4) (Linux). У((void)sizeof(...
него ошибки сexpected identifier or '(' before 'void'
иexpected ')' before 'sizeof'
. Но в принципеsize_t x = (sizeof(...
вместо этого работает так, как задумано. Вы должны каким-то образом «использовать» результат. Чтобы это можно было вызывать несколько раз либо внутри функции, либо в глобальной области видимости, что-то вродеextern char _BUILD_BUG_ON_ [ (sizeof(...) ];
может использоваться повторно (без побочных эффектов,_BUILD_BUG_ON_
нигде не ссылайтесь).Нет. Условные директивы принимают ограниченный набор условных выражений;
sizeof
это одна из недопустимых вещей.Директивы предварительной обработки оцениваются до анализа источника (по крайней мере, концептуально), поэтому пока нет никаких типов или переменных, чтобы получить их размер.
Однако существуют методы получения утверждений времени компиляции в C (например, см. Эту страницу ).
источник
Я знаю, что это поздний ответ, но чтобы добавить к версии Майка, вот версия, которую мы используем, которая не выделяет никакой памяти. Я не придумал проверку оригинального размера, я нашел ее в Интернете много лет назад и, к сожалению, не могу ссылаться на автора. Два других - просто продолжение той же идеи.
Поскольку они относятся к typedef, ничего не выделяется. С __LINE__ в имени это всегда другое имя, поэтому его можно скопировать и вставить там, где это необходимо. Это работает в компиляторах MS Visual Studio C и компиляторах GCC Arm. Это не работает в CodeWarrior, CW жалуется на переопределение, не используя конструкцию препроцессора __LINE__.
источник
#define STATIC_ASSERT(condition) typedef char p__LINE__[ (condition) ? 1 : -1];
Я знаю, что эта ветка действительно старая, но ...
Мое решение:
Пока это выражение равно нулю, оно компилируется нормально. Что-нибудь еще, и оно тут же взорвется. Поскольку переменная extern'd, она не будет занимать места, и пока на нее никто не ссылается (а они не будут), это не вызовет ошибку ссылки.
Не такой гибкий, как макрос assert, но я не смог заставить его скомпилировать в моей версии GCC, и это будет ... и я думаю, что он будет компилироваться где угодно.
источник
Существующие ответы просто показывают, как добиться эффекта «утверждений времени компиляции» в зависимости от размера типа. Это может удовлетворить потребности OP в данном конкретном случае, но есть и другие случаи, когда вам действительно нужен условный препроцессор, основанный на размере типа. Вот как это сделать:
Напишите себе небольшую программу на C, например:
Скомпилируйте это. Напишите сценарий на вашем любимом языке сценариев, который запускает указанную выше программу C и фиксирует ее вывод. Используйте этот вывод для создания файла заголовка C. Например, если вы использовали Ruby, это могло бы выглядеть так:
Затем добавьте правило в свой Makefile или другой скрипт сборки, которое заставит его запустить приведенный выше скрипт для сборки
sizes.h
.Включайте
sizes.h
везде, где вам нужно использовать условные выражения препроцессора на основе размеров.Готово!
(Вы когда-нибудь печатали
./configure && make
для создания программы? Чтоconfigure
делают скрипты, в основном такие же, как и выше ...)источник
А как насчет следующего макроса:
Например, в комментарии MSVC сообщает что-то вроде:
источник
#if
директиве препроцессора.В качестве ссылки для этого обсуждения я сообщаю, что некоторые компиляторы получают время препроцессора sizeof () ar.
Ответ Джеймса МакНеллиса правильный, но некоторые компиляторы проходят через это ограничение (это, вероятно, нарушает строгий ответ).
В качестве примера я имею в виду C-компилятор IAR (вероятно, ведущий для профессионального программирования микроконтроллеров / встроенных программ).
источник
sizeof
во время предварительной обработки.sizeof
следует рассматривать как просто идентификатор.#if (sizeof(int) == 8)
самом деле, работали (на некоторых компиляторах)». Ответ: «Должно быть, было до меня», - от Денниса Ричи.#define SIZEOF(x) ((char*)(&(x) + 1) - (char*)&(x))
может работатьисточник
#define SIZEOF_TYPE(x) (((x*)0) + 1)
#if
условии. Это не дает никакой выгодыsizeof(x)
.В C11
_Static_assert
добавлено ключевое слово. Его можно использовать как:источник
В моем переносимом коде на C ++ ( http://www.starmessagesoftware.com/cpcclibrary/ ) я хотел защитить размеры некоторых из моих структур или классов.
Вместо того, чтобы найти способ, чтобы препроцессор выдал ошибку (которая не может работать с sizeof (), как указано здесь), я нашел здесь решение, которое заставляет компилятор выдавать ошибку. http://www.barrgroup.com/Embedded-Systems/How-To/C-Fixed-Width-Integers-C99
Мне пришлось адаптировать этот код, чтобы он выдавал ошибку в моем компиляторе (xcode):
источник
После тестирования упомянутого макроса этот фрагмент, похоже, дает желаемый результат (
t.h
):Бег
cc -E t.h
:Бег
cc -o t.o t.h
:В конце концов, 42 - это не ответ на все вопросы ...
источник
Чтобы проверить во время компиляции размер структур данных на соответствие их ограничениям, я использовал этот трюк.
Если размер x больше или равен предельному значению MAX_SIZEOF_X, тогда gcc будет жаловаться на ошибку «размер массива слишком большой». VC ++ выдаст либо ошибку C2148 («общий размер массива не должен превышать 0x7fffffff байтов»), либо C4266 «не может выделить массив постоянного размера 0».
Эти два определения необходимы, потому что gcc позволит таким образом определить массив нулевого размера (sizeof x - n).
источник
sizeof
Оператор не доступен для препроцессора, но вы можете передатьsizeof
компилятору и проверить состояние во время выполнения:источник
compiler_size
служит определение ? Что ваш пример пытается показать?