无需编译即可确定“sizeof float”

发布于 2024-11-30 23:27:09 字数 202 浏览 3 评论 0原文

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

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

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

I'd like to know the size of a float in GCC, without having to run the compiler. I know one option is to write a small function and have the compiler print out an assembly listing.

There is limits.h, which contains the minimums and maximums, but is there something similar that tells the size of the different implicit types?

I'm using GCC on Windows 7 x64; the target platform is ARM7 32 bit mode. Language is C.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

红颜悴 2024-12-07 23:27:09

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

You can have GCC print out all of the default macros:

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

Then you get lines like:

#define __FLT_MANT_DIG__ 24
#define __FLT_MAX_EXP__ 128

Now you can parse this as follows:

24 + lg(128) + 1 = 32

To find documentation:

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) the actual macros:

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

静谧 2024-12-07 23:27:09

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

自从您指定了 GCC 以来,这个答案就更加明确了。 GCC 不支持 float 不是 32 位的任何目标。

The answer is 4. Any reasonable C implementation conforms to IEEE 754, which defines float ("single precision") as a 32-bit binary floating point type with 1 sign bit, 23 mantissa bits, and 8 exponent bits. You will never encounter anything different from this in the real world.

This answer is even more definitive since you specified GCC. GCC does not support any targets where float is not 32-bit.

°如果伤别离去 2024-12-07 23:27:09

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

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

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

一些主要的限制是:

  • 它非常糟糕,
  • 它以一种可怕的方式告诉你信息
  • ,它只适用于可以表示为单个单词的类型(因此 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 个字节
  • < code>long double 是 12 个字节
  • struct foo 是 8 个字节
  • struct bar 是 12 个字节(与 struct foo 不同,因为对齐/填充差异)

希望这有帮助。实际上,有时我会想要这个......一般来说,如果我对嵌入式目标上的结构大小感到好奇,我会在调试器中查找该信息,或者我必须破解调试 printf() 某处。

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

  • 想知道有多大的东西,
  • SAY_SIZEOF() 'call' 放入源文件中
  • ,按 Shift-Ctrl-B (或编译/构建的任何热键) ),获取信息,然后
  • 删除 SAY_SIZEOF() 'call'

Assuming that you just want this to help you determine what the size of various types on your target system is without having to actually run a program on the target system, but you don't intend on this being some sort of tool integrated into a build system, I may have a hack for you...

The hack does require running the compiler to compile a program, but you don't have to run the compiled output anywhere. In fact, this hack is designed to tell you what you want to know by generating compiler errors.

The little macro here will cause the compiler to spit out an error message that corresponds to the size of the type given. It'll also spit out an error message about the 'end of the search' just in case you pass it a type that's larger than what it checks. That's just a 'convenience' to remind you to go add a bunch more lines to the macro so it'll handle the type you're curious about.

Some of the main limitations are:

  • it's horribly hacky
  • it tells you the information in a god-awful way
  • it'll only work with types that can be expressed as a single word (so a typedef is necessary for things like long double as shown in the example).

But if you're ever curious about the size of some type, and don't want to actually run a program on the target to printf() the information, this may help.

Here's the macro(s) along with some examples of it being used:

#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;
}

And here's what compiling that program with GCC/MinGW 4.5.1 says:

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

So, you can easily see that:

  • float is 4 bytes
  • long double is 12 bytes
  • struct foo is 8 bytes
  • struct bar is 12 bytes (different than struct foo due to alignment/padding differences)

Hope this helps. Actually, there have been times when I would want this... Generally, if I'm curious about the size of a struct on my embedded targets I poke around in the debugger for that info or I have to hack in a debug printf() somewhere.

I think this would actually be easier to use:

  • wonder how big something is
  • drop a SAY_SIZEOF() 'call' into the source file
  • hit Shift-Ctrl-B (or whatever the hotkey is to compile/build), get the info, and
  • delete the SAY_SIZEOF() 'call'
太傻旳人生 2024-12-07 23:27:09

另一个选择可能是 gdb:无需任何程序即可运行它并执行 sizeof(float)。问题是你的目标平台和主机平台不一样,所以你必须在你的arm-gdb上运行它们。

Another option could be gdb: Just run it without any program and execute sizeof(float). The problem is that your target and host platform are not the same, so you would have to run them on your arm-gdb.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文