【问题标题】:Determine `sizeof float` without compilation在不编译的情况下确定`sizeof float`
【发布时间】:2011-11-02 08:25:04
【问题描述】:

我想知道 GCC 中 float 的大小,而无需运行编译器。我知道一个选择是编写一个小函数并让编译器打印出一个汇编列表。

limits.h,它包含最小值和最大值,但是有没有类似的东西可以告诉不同隐式类型的大小?

我在 Windows 7 x64 上使用 GCC;目标平台是 ARM7 32 位模式。语言是 C。

【问题讨论】:

  • 答案是 42...
  • FWIW 看起来像 Autoconf resorts to compilation
  • @Tomalak Gert'kal:是的,这是关于 GCC 以及如何找到给定平台的原始类型的大小。
  • 好的,关于 ARM 真的没什么。也不是 C++...
  • sizeof(float) 有什么问题?

标签: c gcc sizeof


【解决方案1】:

您可以让 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

【讨论】:

  • 任何man 页面或命令行帮助选项?我在网络手册上找不到任何内容。
  • 顺便说一句,如果您需要一个宏来在预处理器时计算__FLT_MAX_EXP__ 的日志基数 2,请尝试调整:stackoverflow.com/a/4589384/379897
【解决方案2】:

答案是 4。任何合理的 C 实现都符合 IEEE 754,它将float(“单精度”)定义为具有 1 个符号位、23 个尾数位和 8 个指数位的 32 位二进制浮点类型.在现实世界中,你永远不会遇到任何与此不同的事情。

由于您指定了 GCC,因此这个答案更加明确。 GCC 不支持float 不是 32 位的任何目标。

【讨论】:

    【解决方案3】:

    假设您只是希望它帮助您确定目标系统上各种类型的大小,而不必在目标系统上实际运行程序,但您不打算将其作为某种集成工具进入构建系统,我可能会为您提供 hack...

    hack 确实需要运行编译器来编译程序,但您不必在任何地方运行编译后的输出。事实上,这个 hack 旨在通过生成编译器错误告诉您您想知道的内容。

    这里的小宏会导致编译器吐出对应给定类型大小的错误信息。它还会吐出一条关于“搜索结束”的错误消息,以防你传递给它的类型大于它检查的类型。这只是提醒您向宏添加更多行以便处理您感兴趣的类型的“方便”。

    一些主要限制是:

    • 这太骇人听闻了
    • 它以一种可怕的方式告诉你信息
    • 它仅适用于可以表示为单个单词的类型(因此,typedeflong 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 不同,由于对齐/填充差异)

    希望这会有所帮助。实际上,有时我会想要这个...通常,如果我对嵌入式目标上的结构的大小感到好奇,我会在调试器中四处寻找该信息,或者我必须在调试中破解@987654331 @某处。

    我认为这实际上会更容易使用:

    • 想知道有多大
    • SAY_SIZEOF()“调用”放到源文件中
    • 按 Shift-Ctrl-B(或任何用于编译/构建的热键),获取信息,然后
    • 删除SAY_SIZEOF()“通话”

    【讨论】:

    • 这是一个很棒的技巧!我有时不得不使用static_assert(sizeof(x) &gt; X) 求助于“手动二进制搜索”-> 编译、冲洗并重复。这是更好的负载!当加载和运行需要一段时间时,例如一个嵌入式目标,在编译时能够知道sizeof 的东西通常很好。
    【解决方案4】:

    另一个选项可能是 gdb:只需在没有任何程序的情况下运行它并执行 sizeof(float)。问题是你的目标平台和宿主平台不一样,所以你必须在你的 arm-gdb 上运行它们。

    【讨论】:

      猜你喜欢
      • 2018-04-28
      • 2013-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-02
      • 2016-09-30
      • 2012-04-19
      • 1970-01-01
      相关资源
      最近更新 更多