这个简单的代码:
#define WIDTH 500.5
#define NB 23.2
int x[(int)(WIDTH/NB)];
Run Code Online (Sandbox Code Playgroud)
给我一个警告:
prog.c:4:1: warning: variably modified 'x' at file scope [enabled by default]
Run Code Online (Sandbox Code Playgroud)
如果我设置#define WIDTH 500和#define NB 23,警告消失.
为WIDTH编译器传递宏强制评估浮点值,从而发出警告,因为数组没有常量大小.
预处理的C代码看起来像int x[(int)(500.5/23.2)];,但int x[(int)(500/23)];对于编译器是可以的(值已经是常量整数)
我也希望找到一种方法
-Werror:似乎这是一个失败的原因:GCC,C:找出在#pragma中使用的默认警告名称忽略有趣的事情:编译g++我没有警告,而我在这里读到可变长度数组在C++中没有正式支持,仅在C99中.但这对我来说不是一个选择,因为我需要坚持C.
可以确保像这样创建一个普通数组(非 VLA):
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
enum{ARRAY_DIMENSION_OF_x = (int)(WIDTH/NB)};
int x[ARRAY_DIMENSION_OF_x];
#pragma GCC diagnostic pop
Run Code Online (Sandbox Code Playgroud)
在 gcc 和 clang 的 C 模式下编译时不会发出警告,old-style cast to 'int'在 C++ 模式下会发出警告。
还可以在宏中隐藏枚举的创建:
/* ================= define MAKE_CONST_INT() macro ================= */
#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))) /* +0L avoids "useless cast" warning*/
#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
/* ================= test MAKE_CONST_INT() macro ================= */
#define WIDTH 500.5
#define NB 23.2
extern int x[MAKE_CONST_INT(WIDTH/NB)];
Run Code Online (Sandbox Code Playgroud)
这在 gcc 和 Clang 以及 C++ 模式下编译时不会发出警告。
具有 int 虚拟成员的结构仅需要获得 gcc 接受编译指示的位置_Pragma("GCC diagnostic ....")。
适用于 MSVC、gcc、clang 和 icc的扩展实现,但仍然无法在非常挑剔的编译器上进行编译:
/* ================= define MAKE_CONST_INT() macro ================= */
#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))) /* +0L avoids "useless cast" warning*/
#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 /*other compilers will not disable warning*/
# 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
/* ================= test MAKE_CONST_INT() macro ================= */
#define WIDTH 500.5
#define NB 23.2
extern int x[MAKE_CONST_INT(WIDTH/NB)];
Run Code Online (Sandbox Code Playgroud)