Home > Blockchain >  C vs C why is this macro not expanded to a constant?
C vs C why is this macro not expanded to a constant?

Time:11-18

I am using gcc/g . The below code compiles fine with gcc -S test.c, however with g -S test.cpp I get error: requested alignment is not an integer constant. If I look at the preprocessor output for both it looks identical. So my question is why isn't ALIGN_BYTES being evaluated to the constant 64 by the preprocessor in the C case? (If I replace ALIGN_BYTES with the constant 64 it works fine)

/* test.c, test.cpp */
#define BITS 512
#define ALIGN_BYTES (BITS / 8)

#define ALIGN __attribute__ ((aligned(ALIGN_BYTES)))

typedef char* ALIGN char_PT;

CodePudding user response:

As @Deduplicator suggested, __attribute__ is a gcc extension. Using the below fixed the problem.

#ifdef __cplusplus
#define ALIGN alignas(ALIGN_BYTES)
#else
#define ALIGN __attribute__ ((aligned(ALIGN_BYTES)))
#endif

CodePudding user response:

It is not a macro expansion issue. The macro is not expanded to a constant in either C or C , here. The preprocessor does not do arithmetic, so it simply generates the expression 512 / 8 which isn't a constant, but which the compiler should definitely be able to reduce to one.

The preprocessor generates the same code for C and C here, but GCC (for reasons I do not understand) treats the __attribute__ extension differently in the two languages. I really have no idea why, there likely are good reasons, but someone else will have to explain that.

If you compile C, gcc is happy with aligned((512 / 8)), but if you compile C with g it will complain that 512 / 8 is not a constant. It is right, I guess, but really also wrong.

There are other cases where it is the opposite, where g is happy with a non-constant, but gcc is not. If you declare a static const int for example, you can use it in __attribute__((aligned(...)) in C but not in C. Again, I cannot explain why. It's a compiler extension and GCC can do whatever. And for some reason, it will treat the two languages differently here.

/* g   will complain about this one; gcc will not */
typedef char *__attribute__((aligned((512 / 8)))) char_PT;

/* gcc will complain about this one; g   will not */
static const int A = 16;
typedef char *__attribute__((aligned(A))) char_PT2;

I suppose, though, that since we know one version that works with C and another that works with C , we could do this:

#include <stdalign.h> /* for C */

#define BITS 512

#ifdef __cplusplus
static const unsigned int ALIGN_BYTES = BITS / 8;
#define ALIGN __attribute__((aligned(ALIGN_BYTES)))
#else /* C */
#define ALIGN_BYTES (BITS / 8)
#define ALIGN __attribute__((aligned(ALIGN_BYTES)))
#endif

typedef char *ALIGN char_PT;
  • Related