你可以通过以下方式确保创建一个普通数组(非VLA):
enum{ARRAY_DIMENSION_OF_x = (int)(WIDTH/NB)};
int x[ARRAY_DIMENSION_OF_x];
这段代码在gcc和clang的C模式下编译时没有警告,但在C++模式下使用旧式强制转换时会有“int”的警告。
也可以通过宏来隐藏枚举类型的创建:
#ifdef __cplusplus
template<class T> struct make_const_int_helper{static T t;};
# define MAKE_CONST_INT(x) (sizeof(*(make_const_int_helper<char (*)[int((x)+0L)]>::t)))
#else
# define EVALUATE_TO_0(type) (0*__builtin_types_compatible_p(type,int))
# define EVALUATE_TO_0_PRAGMA(x) EVALUATE_TO_0(struct{int dummy; _Pragma(x)})
# define EVALUATE_TO_0_START_DISABLE_WARNINGS \
( EVALUATE_TO_0_PRAGMA("GCC diagnostic push") \
+ EVALUATE_TO_0_PRAGMA("GCC diagnostic ignored \"-Wpedantic\"") \
+ EVALUATE_TO_0_PRAGMA("GCC diagnostic ignored \"-Wc++-compat\"") )
# define EVALUATE_TO_0_END_DISABLE_WARNINGS \
EVALUATE_TO_0_PRAGMA("GCC diagnostic pop")
# define MAKE_CONST_INT(x) MAKE_CONST_INT_HELPER2(x,__LINE__,__COUNTER__)
# define MAKE_CONST_INT_HELPER2(x,line,counter) MAKE_CONST_INT_HELPER(x,line,counter)
# define MAKE_CONST_INT_HELPER(x,line,counter) \
( EVALUATE_TO_0_START_DISABLE_WARNINGS \
+ EVALUATE_TO_0(enum{ INT_CONSTANT_##counter##_AT_LINE_##line = (int)(x) }) \
+ INT_CONSTANT_##counter##_AT_LINE_##line \
+ EVALUATE_TO_0_END_DISABLE_WARNINGS)
#endif
#define WIDTH 500.5
#define NB 23.2
extern int x[MAKE_CONST_INT(WIDTH/NB)];
这段代码在gcc和clang的C和C++模式下编译时不会出现警告。
带有int dummy成员的结构体仅是为了获得一个位置,以便gcc接受
_Pragma("GCC diagnostic ....")
预处理指令。
示例
扩展实现适用于MSVC、gcc、clang和icc,但仍无法在非常挑剔的编译器上编译:
#ifdef __cplusplus
# if defined(__GNUC__) && !defined(__clang__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wtemplates"
# endif
template<class T> struct make_const_int_helper{static T t;};
# if defined(__GNUC__) && !defined(__clang__)
# pragma GCC diagnostic pop
# endif
# define MAKE_CONST_INT(x) (sizeof(*(make_const_int_helper<char (*)[int((x)+0L)]>::t)))
#else
# if defined(__GNUC__)
# define EVALUATE_TO_0(type) (0*__builtin_types_compatible_p(type,int))
# define EVALUATE_TO_0_PRAGMA(x) EVALUATE_TO_0(struct{int dummy; _Pragma(x)})
# define EVALUATE_TO_0_START_DISABLE_WARNINGS \
( EVALUATE_TO_0_PRAGMA("GCC diagnostic push") \
+ EVALUATE_TO_0_PRAGMA("GCC diagnostic ignored \"-Wpedantic\"") \
+ EVALUATE_TO_0_PRAGMA("GCC diagnostic ignored \"-Wc++-compat\"") )
# define EVALUATE_TO_0_END_DISABLE_WARNINGS \
EVALUATE_TO_0_PRAGMA("GCC diagnostic pop")
# else
# define EVALUATE_TO_0(type) (0*sizeof(type))
# if defined(_MSC_VER)
# define EVALUATE_TO_0_START_DISABLE_WARNINGS \
(0 __pragma(warning( push )) __pragma(warning(disable:4116)))
# define EVALUATE_TO_0_END_DISABLE_WARNINGS (0 __pragma(warning( pop )) )
# else
# define EVALUATE_TO_0_START_DISABLE_WARNINGS 0
# define EVALUATE_TO_0_END_DISABLE_WARNINGS 0
# endif
# endif
# define MAKE_CONST_INT(x) MAKE_CONST_INT_HELPER2(x,__LINE__,__COUNTER__)
# define MAKE_CONST_INT_HELPER2(x,line,counter) MAKE_CONST_INT_HELPER(x,line,counter)
# define MAKE_CONST_INT_HELPER(x,line,counter) \
( EVALUATE_TO_0_START_DISABLE_WARNINGS \
+ EVALUATE_TO_0(enum{ INT_CONSTANT_##counter##_AT_LINE_##line = (int)(x) }) \
+ INT_CONSTANT_##counter##_AT_LINE_##line \
+ EVALUATE_TO_0_END_DISABLE_WARNINGS)
#endif
#define WIDTH 500.5
#define NB 23.2
extern int x[MAKE_CONST_INT(WIDTH/NB)];
int x[(int)((int)WIDTH+((int)NB+1))/(int)NB];
- 可能会浪费一些字节,但有趣的是可以摆脱警告,并分配(可能比所需更多的)整数。 - tofroint x[((int)WIDTH+1)/(int)NB];
,因为((int)WIDTH+1) > WIDTH
,而且除以比NB小的数也可以工作。 - Jean-François FabreWIDTH + 1
会导致问题,除非你总是想要一个更多(或者可以容忍它)。 - too honest for this site