Как я могу напечатать результат sizeof() во время компиляции в C?
Как я могу напечатать результат sizeof() во время компиляции в C?
В настоящее время я использую статическое утверждение (домашнее заваривание на основе других веб-ресурсов), чтобы сравнить результат sizeof() с различными константами. Пока это работает... это далеко не изящно или быстро. Я также могу создать экземпляр переменной/структуры и посмотреть в файле карты, но это также менее элегантно и быстро, чем прямой вызов/команда/оператор. Кроме того, это встроенный проект с использованием нескольких кросс-компиляторов... поэтому создание и загрузка примерной программы в цель, а затем считывание значения еще более затруднительно, чем любой из вышеперечисленных.
В моем случае (старый GCC) #warning sizeof(MyStruct)
фактически не интерпретирует sizeof() перед печатью предупреждения.
Ответы
Ответ 1
Я слонялся вокруг в поисках подобной функциональности, когда наткнулся на это:
Можно ли распечатать размер класса C++ во время компиляции?
Что дало мне идею для этого:
char (*__kaboom)[sizeof( YourTypeHere )] = 1;
Что приводит к следующему предупреждению в VS2015:
warning C4047: 'initializing': 'DWORD (*)[88]' differs in levels of indirection from 'int'
где 88 в этом случае будет размер, который вы ищете.
Супер хаки, но это делает свое дело. Возможно, на пару лет поздно, но, надеюсь, это кому-нибудь пригодится.
У меня еще не было возможности попробовать gcc или clang, но я постараюсь подтвердить, работает ли он, если кто-то до меня не добрался.
Изменение: работает из коробки для Clang 3.6
Единственная уловка, которую я мог получить для работы в GCC, это злоупотребление -Wformat
и наличие макроса, определяющего функцию, подобную следующей:
void kaboom_print( void )
{
printf( "%d", __kaboom );
}
Который даст вам предупреждение, как:
...blah blah blah... argument 2 has type 'char (*)[88]'
Чуть более грубый, чем первоначальное предложение, но, возможно, кто-то, кто знает gcc немного лучше, может придумать лучшее предупреждение для злоупотреблений.
Ответ 2
Все, что вам нужно, это хитрость, которая заставляет компилятор жаловаться на то, что некоторые целочисленные значения времени компиляции используются неправильно, например, дублированная константа case
:
struct X {
int a,b;
int c[10];
};
int _tmain(int argc, _TCHAR* argv[])
{
int dummy;
switch (dummy) {
case sizeof(X):
case sizeof(X):
break;
}
return 0;
}
Результат компиляции:
------ Build started: Project: cpptest, Configuration: Debug Win32 ------
cpptest.cpp c:\work\cpptest\cpptest\cpptest.cpp(29): error C2196: case value '48' already used
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Таким образом, размер структуры X составляет 48
Ответ 3
Еще один способ (который на самом деле работает):
char __foo[sizeof(MyStruct) + 1] = {[sizeof(MyStruct)] = ""};
Работает с old'ish gcc 5.x. Выдает ошибку, подобную этой:
a.c:8:54: error: initializer element is not computable at load time
a.c:8:54: note: (near initialization for 'a[8]')
ps, очевидно, этот (очень) специфичен для gcc. Все остальные методы не работают для меня.
Ответ 4
Следующий способ, который работает в GCC, Clang, MSVC и других, даже в более старых версиях, основан на неудачном преобразовании параметра функции из указателя в массив в скалярный тип. Компиляторы определяют размер массива, так что вы можете получить значение из выходных данных. Работает как в режиме C, так и в режиме C++.
Пример кода, чтобы узнать sizeof(long)
(играть с ним онлайн):
char checker(int);
char checkSizeOfInt[sizeof(long)]={checker(&checkSizeOfInt)};
Примеры соответствующих результатов:
<source>:1: note: expected 'int' but argument is of type 'char (*)[8]'
<source>:1:6: note: candidate function not viable: no known conversion from 'char (*)[8]' to 'int' for 1st argument;
<source>(2): warning C4047: 'function': 'int' differs in levels of indirection from 'char (*)[4]'
Ответ 5
Я наткнулся на решение, подобное Bakhazard отличному решению, и этот менее подробное предупреждение, поэтому вы можете счесть это полезным:
char (*__fail)(void)[sizeof(uint64_t)] = 1;
Выдает сообщение об ошибке
Function cannot return array type 'char [8]'
Это было протестировано с последней версией clang(1)
.
Ответ 6
Мой компилятор gcc C отказывается печатать размер, используя любое из вышеперечисленных решений. Я перевернул логику, чтобы ввести предупреждения компилятора для какого размера это не так.
enum e
{
X = sizeof(struct mystruct)
};
void foo()
{
static enum e ev;
switch (ev)
{
case 0:
case 4:
case 8:
case 12:
case 16:
case 20:
break;
}
}
Затем я должен просмотреть предупреждения о недостающем числе.
warning: case value '0' not in enumerated type 'e' [-Wswitch]
warning: case value '4' not in enumerated type 'e' [-Wswitch]
warning: case value '12' not in enumerated type 'e' [-Wswitch]
warning: case value '16' not in enumerated type 'e' [-Wswitch]
warning: case value '20' not in enumerated type 'e' [-Wswitch]
Итак, размер моей структуры равен 8.
Моя упаковка 4.
Мех... это вариант.
Ответ 7
Хотя это не совсем во время компиляции, это до запуска, поэтому оно может быть актуальным для некоторых людей.
Вы можете определить такой массив:
uint8_t __some_distinct_name[sizeof(YourTypeHere)];
И затем, после компиляции, получите размер из объектного файла:
$ nm -td -S your_object_file | # list symbols and their sizes, in decimal
grep ' __some_distinct_name$' | # select the right one
cut -d' ' -f2 | # grab the size field
xargs printf "Your type is %d B\n" # print
Ответ 8
@jws
хорошая идея!. Однако sizeof (xxx) является константным выражением (кроме VLA, https://en.cppreference.com/w/c/language/sizeof), поэтому оператор sizeof должен работать даже в случае выбора:
enum e1 {dummy=-1};
enum e1 ev;
switch (ev) {
case sizeof(myType):;
break;
default:;
}
.. он работает в моем GCC: "..\находящихсяreads.c: 18: 9: предупреждение: значение регистра '4' отсутствует в перечисляемом типе 'enum e1' [-Wswitch]"
Ответ 9
Вы не можете сделать это, а не со структурами. Препроцессор вызывается перед компиляцией, поэтому нет даже концепции структуры; вы не можете оценить размер того, что не существует/не определено. Препроцессор делает токенизацию единицы перевода, но он делает это только с целью обнаружения вызова макроса.
Самое близкое, что вы можете сделать, это полагаться на некоторые макросы, определенные при реализации, которые оценивают размер встроенных типов. В gcc вы можете найти те, у кого:
gcc -dM -E - </dev/null | grep -i size
Что в моей системе напечатано:
#define __SIZE_MAX__ 18446744073709551615UL
#define __SIZEOF_INT__ 4
#define __SIZEOF_POINTER__ 8
#define __SIZEOF_LONG__ 8
#define __SIZEOF_LONG_DOUBLE__ 16
#define __SIZEOF_SIZE_T__ 8
#define __SIZEOF_WINT_T__ 4
#define __SIZE_TYPE__ long unsigned int
#define __SIZEOF_PTRDIFF_T__ 8
#define __SIZEOF_FLOAT__ 4
#define __SIZEOF_SHORT__ 2
#define __SIZEOF_INT128__ 16
#define __SIZEOF_WCHAR_T__ 4
#define __SIZEOF_DOUBLE__ 8
#define __SIZEOF_LONG_LONG__ 8
Нет ничего, что можно было бы узнать, чтобы узнать размер настраиваемой структуры без написания программы и ее выполнения.