开发者

Determine `sizeof float` without compilation

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 x6开发者_C百科4; the target platform is ARM7 32 bit mode. Language is C.


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


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.


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'


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜