Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compile-time sizeof conditional

I want to define a macro if a condition involving sizeof is true and do nothing (but still compile) if it is false. If the preprocessor supported sizeof, it would look like this:

#if (sizeof(void*) <= sizeof(unsigned int)) // what goes here?
#  define POINTER_FITS_INTO_UINT
#endif

There are some pages (e.g. http://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/) which explain how to make a compile-time assertion on sizeof (and fail to compile if it fails), but I don't see a way to extend this approach to what I want.

like image 780
Alexey Romanov Avatar asked Dec 07 '10 07:12

Alexey Romanov


People also ask

Does sizeof work at compile time?

sizeof is evaluated at compile time, but if the executable is moved to a machine where the compile time and runtime values would be different, the executable will not be valid.

Can we define a macro at compile time?

You can define any macro on the compiler command line with -D. Use that to specify the model or variant you want, and based on that, #ifdefs in the code enable the other relevant macros.

What is sizeof () in C macro?

The sizeof is a unary operator in C/C++ programming language, it is used to get the occupied size of a variable, constant, expression, data type, etc. It returns an unsigned integral type (size_t).


2 Answers

You just can't do it. sizeof is a compile time operator. #if and #define and preprocessor related. As the preprocessor runs BEFORE the compiler this just won't work. You may, however, be able to find an arcane compiler switch that will allow you to multi pass it (ie preprocess, pretend compile, preprocess, compile) but, in all fairness, I'd give up trying to do what you want. Its not meant to work and, simply, it doesn't.

Your best best is to set such defines as -D commands passed to the compiler. You can statically assert that the ones chosen are correct. This way you just have to set up a few defines externally for a given compile mode (eg PowerPC Release) and so on.

like image 152
Goz Avatar answered Oct 13 '22 09:10

Goz


The correct solution to your problem is to use the C99 standard headers:

#include <stdint.h>
#include <inttypes.h>

You only need one of the two because #include <inttypes.h> includes the material from #include <stdint.h>; however, a lot of the material in <inttypes.h> is only relevant to formatted I/O with scanf() and printf().

Given the putative condition:

#if (sizeof(void*) <= sizeof(unsigned int)) // what goes here?
#  define POINTER_FITS_INTO_UINT
#endif

What you seem to be after is known as:

uintptr_t

That is the unsigned integer type that is big enough to hold any pointer (that is, any data pointer in the C standard; POSIX imposes an additional rule that it must also be big enough to hold function pointers too). The type uintptr_t is defined in <stdint.h>.

If you are subsequently going to be printing such values, or raw pointers, you can use the information from <inttypes.h>:

printf("Pointer = 0x%" PRIXPTR "\n", uintptr_value);
printf("Pointer = 0x%" PRIXPTR "\n", (uintptr_t)any_pointer);
like image 33
Jonathan Leffler Avatar answered Oct 13 '22 07:10

Jonathan Leffler