如何禁用此特定警告
how to disable this particular warning
这个简单的代码:
#define WIDTH 500.5
#define NB 23.2
int x[(int)(WIDTH/NB)];
给我一个警告:
prog.c:4:1: warning: variably modified 'x' at file scope [enabled by default]
如果我设置 #define WIDTH 500
和 #define NB 23
,警告就会消失。
为 WIDTH
宏传递浮点值会强制编译器进行计算,因此会发出警告,因为数组的大小不是恒定的。
预处理后的 C 代码看起来像 int x[(int)(500.5/23.2)];
,而 int x[(int)(500/23)];
对编译器来说是可以的(值已经是常数整数)
我也想办法
- 忽略此特定警告(但留下其他警告以便我可以启用
-Werror
:似乎这是一个失败的原因:GCC, C: Finding out name of default warnings for use in #pragma ignore
- 修复代码,使其执行我想要的操作而不会发出警告。
- 强制预处理器以整数形式执行计算
有趣的事情:使用 g++
编译我没有收到警告,而我在这里读到可变长度数组在 C++ 中不受官方支持,仅在 C99 中受支持。但这对我来说不是一个选择,因为我需要坚持使用 C.
只是违反了标准:
Integer constant expression
An integer constant expression is an
expression that consists only of operators other than assignment,
increment, decrement, function-call, or comma, except that cast
operators can only cast arithmetic types to integer types, integer
constants, enumeration constants, character constants, floating
constants, but only if they are immediately used as operands of casts
to integer type
还有:
The following contexts require expressions that are known as integer
constant expressions':
...
- The index in an array designator (since C99)
这里有一个来自 GNU GCC 的例子可以帮助你:
#pragma GCC diagnostic error "-Wuninitialized"
foo(a); /* error is given for this one */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wuninitialized"
foo(b); /* no diagnostic for this one */
#pragma GCC diagnostic pop
foo(c); /* error is given for this one */
#pragma GCC diagnostic pop
foo(d); /* depends on command-line options */
可以确保像这样创建普通数组(非 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
这在 C 模式下的 gcc 和 clang 中编译时没有警告,在 C++ 模式下有 old-style cast to 'int'
警告。
也可以在宏中隐藏枚举的创建:
/* ================= 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)];
这在 gcc 和 C 和 C++ 模式下的 clang 中编译时没有警告。
只有在 gcc 接受 _Pragma("GCC diagnostic ....")
pragma 的地方才需要具有 int 虚拟成员的结构。
Extended implementation 适用于 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)];
这个简单的代码:
#define WIDTH 500.5
#define NB 23.2
int x[(int)(WIDTH/NB)];
给我一个警告:
prog.c:4:1: warning: variably modified 'x' at file scope [enabled by default]
如果我设置 #define WIDTH 500
和 #define NB 23
,警告就会消失。
为 WIDTH
宏传递浮点值会强制编译器进行计算,因此会发出警告,因为数组的大小不是恒定的。
预处理后的 C 代码看起来像 int x[(int)(500.5/23.2)];
,而 int x[(int)(500/23)];
对编译器来说是可以的(值已经是常数整数)
我也想办法
- 忽略此特定警告(但留下其他警告以便我可以启用
-Werror
:似乎这是一个失败的原因:GCC, C: Finding out name of default warnings for use in #pragma ignore - 修复代码,使其执行我想要的操作而不会发出警告。
- 强制预处理器以整数形式执行计算
有趣的事情:使用 g++
编译我没有收到警告,而我在这里读到可变长度数组在 C++ 中不受官方支持,仅在 C99 中受支持。但这对我来说不是一个选择,因为我需要坚持使用 C.
只是违反了标准:
Integer constant expression
An integer constant expression is an expression that consists only of operators other than assignment, increment, decrement, function-call, or comma, except that cast operators can only cast arithmetic types to integer types, integer constants, enumeration constants, character constants, floating constants, but only if they are immediately used as operands of casts to integer type
还有:
The following contexts require expressions that are known as integer constant expressions':
...
- The index in an array designator (since C99)
这里有一个来自 GNU GCC 的例子可以帮助你:
#pragma GCC diagnostic error "-Wuninitialized"
foo(a); /* error is given for this one */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wuninitialized"
foo(b); /* no diagnostic for this one */
#pragma GCC diagnostic pop
foo(c); /* error is given for this one */
#pragma GCC diagnostic pop
foo(d); /* depends on command-line options */
可以确保像这样创建普通数组(非 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
这在 C 模式下的 gcc 和 clang 中编译时没有警告,在 C++ 模式下有 old-style cast to 'int'
警告。
也可以在宏中隐藏枚举的创建:
/* ================= 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)];
这在 gcc 和 C 和 C++ 模式下的 clang 中编译时没有警告。
只有在 gcc 接受 _Pragma("GCC diagnostic ....")
pragma 的地方才需要具有 int 虚拟成员的结构。
Extended implementation 适用于 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)];