1

Suppose I have a header file with lines like this:

#if LONG_BIT != 8 * SIZEOF_LONG
/* 04-Oct-2000 LONG_BIT is apparently (mis)defined as 64 on some recent
 * 32-bit platforms using gcc.  We try to catch that here at compile-time
 * rather than waiting for integer multiplication to trigger bogus
 * overflows.
 */
#error "pp897:  LONG_BIT  definition appears wrong for platform (bad gcc/glibc config?)."
#endif

I would like to output the value of LONG_BIT and SIZEOF_LONG. Is it possible to do this, or is that impossible from a header file?

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
Chozang
  • 178
  • 1
  • 10
  • 1
    Same idea: https://stackoverflow.com/questions/20979565/how-can-i-print-the-result-of-sizeof-at-compile-time-in-c – Eugene Sh. May 09 '19 at 19:36
  • No, they are not variables but instead they are constants. However, you can still output them with std::cout << LONG_BIT; – Lehks May 09 '19 at 19:41
  • @Lehks Adding that just gives me: /awips2/python/include/python2.7/pyport.h:900:1: error: ‘cout’ in namespace ‘std’ does not name a type std::cout << LONG_BIT; ^ – Chozang May 09 '19 at 19:46
  • @EricPostpischil So preprocessor macros can or cannot be output? – Chozang May 09 '19 at 19:51

3 Answers3

3

_Static_assert in C or static_assert in C++ can test conditions and display a string, and the string can be constructed with preprocessor expansions:

#define LONG_BIT    64
#define SIZEOF_LONG 4

#define StringizeHelper(x)  #x
#define Stringize(x)        StringizeHelper(x)

_Static_assert(LONG_BIT == 8 * SIZEOF_LONG,
    "LONG_BIT is " Stringize(LONG_BIT) " but must be 8 * "
    Stringize(SIZEOF_LONG) ".");

Output with Clang:

x.c:7:1: error: static_assert failed "LONG_BIT is 64 but must be 8 * 4."
_Static_assert(LONG_BIT == 8 * SIZEOF_LONG,
^              ~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Copied and pasted your code. Using gcc I get: /awips2/python/include/python2.7/pyport.h:897:15: error: expected constructor, destructor, or type conversion before ‘(’ token _Static_assert(LONG_BIT == 8 * SIZEOF_LONG, – Chozang May 09 '19 at 20:01
  • @Tharpa Are you compiling in [C](https://wandbox.org/permlink/lvJ21KxytEcEvDEO) or [C++](https://wandbox.org/permlink/N7FwO99MWX2E3Thw)? – Bob__ May 09 '19 at 20:15
  • @Bob__, looking at the Makefile, it has a line C++_FLAGS += -fexceptions, so I guess it's C++. – Chozang May 10 '19 at 14:28
1

You have a few values to test in that case. You could test the plausible ones one by one like a switch/case statement, with a default just in case.

Standalone example. The 2 first define statements are here for the test, remove from final code

// completely bogus/incoherent values just to test
#define LONG_BIT 32
#define SIZEOF_LONG 4444

// operational test from now on    
#if LONG_BIT != 8 * SIZEOF_LONG
#if LONG_BIT == 32
#error "pp897:  LONG_BIT  definition appears wrong for platform (bad gcc/glibc config?): size 32"
#elif LONG_BIT == 64
#error "pp897:  LONG_BIT  definition appears wrong for platform (bad gcc/glibc config?): size 64"
#else
#error "pp897:  LONG_BIT  definition appears wrong for platform (bad gcc/glibc config?): size ???"
#endif
#endif

compilation output:

test.c:7:2: error: #error "pp897:  LONG_BIT  definition appears wrong for platfo
rm (bad gcc/glibc config?): size 32"

This method is compatible with all standards including C89

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
  • It appears that by redefining a value, the compiler will say what it's value was: warning: "SIZEOF_LONG" redefined [enabled by default] #define SIZEOF_LONG 4444 ^ In file included from /acme/python/include/python2.7/Python.h:8:0, from edex_HWR_sfc.C:44: /acme/python/include/python2.7/pyconfig.h:1051:0: note: this is the location of the previous definition #define SIZEOF_LONG 8 – Chozang May 09 '19 at 20:24
  • of course, I did redefine it just to test as the comment states "// completely bogus value just to test" – Jean-François Fabre May 09 '19 at 20:25
  • Not sure why you reiterated that. Nothing in my comment would seem to have prompted that. – Chozang May 10 '19 at 14:25
  • ok, then if you want to redefine a value you have to `#undef` it first. – Jean-François Fabre May 10 '19 at 14:26
  • Thanks. What I meant was, that by attempting to redefine it, the problem is solved -- the attempt causes gcc to display the value I was looking for in its warning! – Chozang May 10 '19 at 18:33
0

With GCC or Clang (at least), you can print out the values of preprocessor macros:

#define LONG_BIT 60
#pragma message "LONG_BIT is " STRINGIFY(LONG_BIT)

But that won't get you the value of sizeof(long), which is not a preprocessor construct. It also won't do arithmetic; LONG_BIT needs to be an actual number for that to produce the desired message.

That doesn't work with #error, which doesn't do macro substitutions in the text.

Here, STRINGIFY has the usual two-stage definition:

#define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x)

You can also write the whole message inside the arguments, at least in this case, but watch out for unexpected expansions:

#pragma message STRINGIFY(LONG BIT is LONG_BIT)
rici
  • 234,347
  • 28
  • 237
  • 341