C vs C++ 为什么这个宏没有扩展为常量?
C vs C++ why is this macro not expanded to a constant?
我正在使用 gcc/g++。下面的代码用 gcc -S test.c
编译得很好,但是用 g++ -S test.cpp
我得到 error: requested alignment is not an integer constant
。如果我查看两者的预处理器输出,它看起来是一样的。所以我的问题是为什么 ALIGN_BYTES
在 C++ 的情况下不被预处理器评估为常量 64? (如果我用常量 64 替换 ALIGN_BYTES
它工作正常)
/* test.c, test.cpp */
#define BITS 512
#define ALIGN_BYTES (BITS / 8)
#define ALIGN __attribute__ ((aligned(ALIGN_BYTES)))
typedef char* ALIGN char_PT;
正如@Deduplicator 所建议的,__attribute__
是一个 gcc 扩展。使用以下解决了问题。
#ifdef __cplusplus
#define ALIGN alignas(ALIGN_BYTES)
#else
#define ALIGN __attribute__ ((aligned(ALIGN_BYTES)))
#endif
不是宏展开的问题。此处,宏未在 C 或 C++ 中扩展为常量。预处理器不做算术运算,所以它只是生成表达式 512 / 8
,它不是常量,但编译器肯定能够将其归约为 1。
预处理器在这里为 C 和 C++ 生成相同的代码,但是 GCC(由于我不明白的原因)在两种语言中对 __attribute__
扩展的处理方式不同。我真的不知道为什么,可能有充分的理由,但其他人必须解释。
如果你编译 C,gcc
对 aligned((512 / 8))
很满意,但如果你用 g++
编译 C++,它会抱怨 512 / 8
不是常量。我猜是对的,但实际上也是错的。
在其他情况下情况正好相反,g++
对非常数满意,但 gcc
不满意。例如,如果声明一个 static const int
,则可以在 C++ 中的 __attribute__((aligned(...))
中使用它,但不能在 C 中使用它。同样,我无法解释原因。它是一个编译器扩展,GCC 可以做任何事情。出于某种原因,它会在这里以不同的方式对待这两种语言。
/* 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;
不过,我想既然我们知道一个版本适用于 C,另一个版本适用于 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;
我正在使用 gcc/g++。下面的代码用 gcc -S test.c
编译得很好,但是用 g++ -S test.cpp
我得到 error: requested alignment is not an integer constant
。如果我查看两者的预处理器输出,它看起来是一样的。所以我的问题是为什么 ALIGN_BYTES
在 C++ 的情况下不被预处理器评估为常量 64? (如果我用常量 64 替换 ALIGN_BYTES
它工作正常)
/* test.c, test.cpp */
#define BITS 512
#define ALIGN_BYTES (BITS / 8)
#define ALIGN __attribute__ ((aligned(ALIGN_BYTES)))
typedef char* ALIGN char_PT;
正如@Deduplicator 所建议的,__attribute__
是一个 gcc 扩展。使用以下解决了问题。
#ifdef __cplusplus
#define ALIGN alignas(ALIGN_BYTES)
#else
#define ALIGN __attribute__ ((aligned(ALIGN_BYTES)))
#endif
不是宏展开的问题。此处,宏未在 C 或 C++ 中扩展为常量。预处理器不做算术运算,所以它只是生成表达式 512 / 8
,它不是常量,但编译器肯定能够将其归约为 1。
预处理器在这里为 C 和 C++ 生成相同的代码,但是 GCC(由于我不明白的原因)在两种语言中对 __attribute__
扩展的处理方式不同。我真的不知道为什么,可能有充分的理由,但其他人必须解释。
如果你编译 C,gcc
对 aligned((512 / 8))
很满意,但如果你用 g++
编译 C++,它会抱怨 512 / 8
不是常量。我猜是对的,但实际上也是错的。
在其他情况下情况正好相反,g++
对非常数满意,但 gcc
不满意。例如,如果声明一个 static const int
,则可以在 C++ 中的 __attribute__((aligned(...))
中使用它,但不能在 C 中使用它。同样,我无法解释原因。它是一个编译器扩展,GCC 可以做任何事情。出于某种原因,它会在这里以不同的方式对待这两种语言。
/* 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;
不过,我想既然我们知道一个版本适用于 C,另一个版本适用于 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;