Определите `sizeof float` без компиляции - PullRequest
15 голосов
/ 24 августа 2011

Я хотел бы знать размер float в GCC, без необходимости запуска компилятора. Я знаю, что один из вариантов - написать небольшую функцию и заставить компилятор распечатать лист сборки.

Существует limits.h, который содержит минимумы и максимумы, но есть ли что-то похожее, что говорит о размере различных неявных типов?

Я использую GCC на Windows 7 x64; целевая платформа - 32-битный режим ARM7. Язык C.

Ответы [ 4 ]

14 голосов
/ 24 августа 2011

GCC можно распечатать все макросы по умолчанию:

gcc -dM -E - </dev/null | grep FLT

Тогда вы получите строки вроде:

#define __FLT_MANT_DIG__ 24
#define __FLT_MAX_EXP__ 128

Теперь вы можете разобрать это следующим образом:

24 + lg(128) + 1 = 32

Чтобы найти документацию:

1) man gcc:

   -E  Stop after the preprocessing stage; do not run the compiler proper.
       The output is in the form of preprocessed source code, which is
       sent to the standard output.

...

   -dCHARS
       CHARS is a sequence of one or more of the following characters, and
       must not be preceded by a space.  Other characters are interpreted
       by the compiler proper, or reserved for future versions of GCC, and
       so are silently ignored.  If you specify characters whose behavior
       conflicts, the result is undefined.

       M   Instead of the normal output, generate a list of #define
           directives for all the macros defined during the execution of
           the preprocessor, including predefined macros.  This gives you
           a way of finding out what is predefined in your version of the
           preprocessor.  Assuming you have no file foo.h, the command

                   touch foo.h; cpp -dM foo.h

           will show all the predefined macros.

2) фактические макросы:

http://www.gnu.org/s/hello/manual/libc/Floating-Point-Parameters.html

9 голосов
/ 24 августа 2011

Ответ 4. Любая разумная реализация C соответствует IEEE 754, который определяет float («одинарная точность») как 32-разрядный двоичный тип с плавающей запятой с 1 знаковым битом, 23 битами мантиссы и 8 битами экспоненты. , Вы никогда не встретите ничего отличного от этого в реальном мире.

Этот ответ еще более окончательный, поскольку вы указали GCC. GCC не поддерживает цели, для которых float не является 32-разрядным.

7 голосов
/ 24 августа 2011

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

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

Небольшой макрос здесь заставит компилятор выдать сообщение об ошибке, соответствующее размеру данного типа. Он также выдаст сообщение об ошибке «конец поиска» на случай, если вы передадите ему тип, который больше, чем тот, который он проверяет. Это просто «удобство», чтобы напомнить вам, что нужно добавить еще несколько строк в макрос, чтобы он обрабатывал интересующий вас тип.

Некоторые из основных ограничений:

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

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

Вот макрос (ы) вместе с некоторыми примерами его использования:

#if !defined( PASTE)
#define PASTE2( x, y) x##y
#define PASTE( x, y)  PASTE2( x, y)
#endif /* PASTE */

#define SAY_IF_SIZEOF( type, size)   static char PASTE( PASTE( PASTE( sizeof_, type), _is_), size) [(sizeof(type) == (size)) ? -1 : 1]
#define SAY_SIZEOF_END(type) static char PASTE( end_search_for_sizeof_, type)[-1]

#define SAY_SIZEOF(type) \
    SAY_IF_SIZEOF( type, 1); \
    SAY_IF_SIZEOF( type, 2); \
    SAY_IF_SIZEOF( type, 3); \
    SAY_IF_SIZEOF( type, 4); \
    SAY_IF_SIZEOF( type, 5); \
    SAY_IF_SIZEOF( type, 6); \
    SAY_IF_SIZEOF( type, 7); \
    SAY_IF_SIZEOF( type, 8); \
    SAY_IF_SIZEOF( type, 9); \
    SAY_IF_SIZEOF( type, 10); \
    SAY_IF_SIZEOF( type, 11); \
    SAY_IF_SIZEOF( type, 12); \
    SAY_IF_SIZEOF( type, 13); \
    SAY_IF_SIZEOF( type, 14); \
    SAY_IF_SIZEOF( type, 15); \
    SAY_IF_SIZEOF( type, 16); \
    SAY_SIZEOF_END(type)


//here's where you get to ask about the size of a type

SAY_SIZEOF(float);

typedef long double long_double;

SAY_SIZEOF(long_double);


struct foo {
    char x;
    short y;
    int* p;
};

struct bar {
    char x;
    int* p;
    short y;
};

typedef struct foo foo_t;
typedef struct bar bar_t;

SAY_SIZEOF(foo_t);
SAY_SIZEOF(bar_t);

int main(void)
{

    return 0;
}

И вот что говорит компиляция этой программы с помощью GCC / MinGW 4.5.1:

C:\temp\test.c:34:1: error: size of array 'sizeof_float_is_4' is negative
C:\temp\test.c:34:1: error: size of array 'end_search_for_sizeof_float' is negative
C:\temp\test.c:38:1: error: size of array 'sizeof_long_double_is_12' is negative
C:\temp\test.c:38:1: error: size of array 'end_search_for_sizeof_long_double' is negative
C:\temp\test.c:56:1: error: size of array 'sizeof_foo_t_is_8' is negative
C:\temp\test.c:56:1: error: size of array 'end_search_for_sizeof_foo_t' is negative
C:\temp\test.c:57:1: error: size of array 'sizeof_bar_t_is_12' is negative
C:\temp\test.c:57:1: error: size of array 'end_search_for_sizeof_bar_t' is negative

Итак, вы можете легко увидеть, что:

  • float - 4 байта
  • long double составляет 12 байтов
  • struct foo составляет 8 байтов
  • struct bar - 12 байтов (отличается от struct foo из-за различий выравнивания / заполнения)

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

Я думаю, что на самом деле это будет проще:

  • интересно, насколько велик что-то
  • сбросить SAY_SIZEOF() 'call' в исходный файл
  • нажмите Shift-Ctrl-B (или любую горячую клавишу для компиляции / сборки), получите информацию и
  • удалить SAY_SIZEOF() 'вызов'
1 голос
/ 24 августа 2011

Другим вариантом может быть gdb: просто запустите его без какой-либо программы и выполните sizeof(float). Проблема в том, что ваша цель и платформа хоста не совпадают, поэтому вам придется запускать их на вашем arm-gdb.

...