如何禁用特定警告提示

6
这段简单的代码:
#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)];对于编译器是可以的(值已经是常量整数)。
我想找到一种方法: 有趣的是:使用g++编译时,我没有收到警告,然而我在这里读到,变长数组在C++中并没有得到官方支持,只在C99中得到了支持。但这对我来说不是一个选项,因为我需要坚持C。

1
预处理器不会对500/23进行计算 - 这是编译器的任务。 - Serge
1
一个简单的“脏”解决方法是:int x[(int)((int)WIDTH+((int)NB+1))/(int)NB]; - 可能会浪费一些字节,但有趣的是可以摆脱警告,并分配(可能比所需更多的)整数。 - tofro
1
@tofro:太好了!甚至可以调整为int x[((int)WIDTH+1)/(int)NB];,因为((int)WIDTH+1) > WIDTH,而且除以比NB小的数也可以工作。 - Jean-François Fabre
  1. 它不会破坏任何东西(除了编译时间的一小部分),因为常量表达式保证在编译时计算。
  2. 最后的转换是不必要的。永远不要没有充分理由使用强制类型转换,如果你不确切知道它们的影响!
- too honest for this site
@Jean-FrançoisFabre:这就是“无关”的意思。顺便说一下:如果没有小数,WIDTH + 1会导致问题,除非你总是想要一个更多(或者可以容忍它)。 - too honest for this site
显示剩余9条评论
3个回答

3

它违反了标准:

整数常量表达式

整数常量表达式是一个仅包含运算符的表达式,除了赋值、递增、递减、函数调用或逗号之外,只有强制类型转换运算符可以将算术类型转换为整数类型、整数常量、枚举常量、字符常量、浮点常量,但只有在它们被立即用作整数类型的强制类型转换的操作数时才能这样做

并且进一步说明:

以下情况需要已知为整数常量表达式的表达式:

...

  • 数组设计器中的索引(自C99起)

2
建议添加引用和/或使用略有不同的C11标准。 - chux - Reinstate Monica

1

你可以通过以下方式确保创建一个普通数组(非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

这段代码在gcc和clang的C模式下编译时没有警告,但在C++模式下使用旧式强制转换时会有“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和clang的C和C++模式下编译时不会出现警告。
带有int dummy成员的结构体仅是为了获得一个位置,以便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)];

-1

这里有一个来自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 */

好的,但在我的特定情况下,关键字是什么: #pragma GCC diagnostic ignored "-Wsomething???" 因为警告本身没有指示如何抑制警告吗?int x[(int)(WIDTH/NB)]; #pragma GCC diagnostic pop - Jean-François Fabre
这里是您可以使用的所有选项列表:gcc-list。我猜您需要以下所有选项:**-Wconversion-Wformat-Wtraditional**。请在附加的列表中进行检查。 - acornagl
这个链接就到此为止了:https://dev59.com/WHDYa4cB1Zd3GeqPFutU - Jean-François Fabre
这并没有真正回答问题。它只是给出了如何通常使用与错误/警告相关的编译指示的建议。它也没有解决问题,因为问题仍然存在。一般来说,强烈建议不要杀死信使(即消除诊断信息),而是在可能的最内层级别上修复问题。 - too honest for this site

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接