初始化复杂结构,GCC 警告:已覆盖副作用的初始化字段

Posted

技术标签:

【中文标题】初始化复杂结构,GCC 警告:已覆盖副作用的初始化字段【英文标题】:Initializing complex structure, GCC warns: initialized field with side-effects overwritten 【发布时间】:2015-02-03 00:53:11 【问题描述】:

我正在编写一个西洋双陆棋位置评估系统,我正在尝试使用指定的初始化器、复合文字和可变参数宏来创建一个关键字参数函数,如 here 和 Ben Klemens 的优秀书籍中所述 21世纪C

// from board.h
typedef struct _board_t board_t;  

// from evaluator.h (evaluator is an "interface" in a primitive object system.)
#define EVALUATOR(v) (evaluator_t*)(v)

enum  OUTPUT_WIN, OUTPUT_WINGAMMON, OUTPUT_WINBACKGAMMON,
       OUTPUT_LOSEGAMMON, OUTPUT_LOSEBACKGAMMON, N_OUTPUT ;

typedef struct _evaluator_t evaluator_t;

// from composite_evaluator.h
#define N_MAX_EVALUATORS_IN_COMPOSITE 10

typedef evaluator_t * (*new_func)( void *d );

typedef struct 
    int n_eval;
    int (*classifier)( const board_t *b );
    struct 
        new_func construct;
        void *args;
     config[N_MAX_EVALUATORS_IN_COMPOSITE];
 composite_evaluator_config_t;

// some evaluator implementations (just decl for _new)
typedef struct _overevaluator_t       overevaluator_t;
typedef struct _onesidebearoff_t      onesidebearoff_t;
typedef struct _neuralnet_evaluator_t neuralnet_evaluator_t;
overevaluator_t        *overevaluator_new       (void *args);
onesidebearoff_t       *onesidebearoff_new      (void *args);
neuralnet_evaluator_t  *neuralnet_evaluator_new (void *args);

// and a classifing function decl.
int classify_position( const board_t *b );

// Example from main program
#include <stdio.h>
int main()

    // This is of course coded in a variadic macro, but the macro is left out for simplicity of the example.
    composite_evaluator_config_t myeval = 
        .n_eval = 5,
        .classifier = classify_position,
        .config = 
          [0] =  .construct = (new_func)overevaluator_new ,
          [1] =  .construct = (new_func)onesidebearoff_new ,
          [2] =  .construct = (new_func)neuralnet_evaluator_new, .args = &((char*[])"race.weights", "race", "race") ,
          [3] =  .construct = (new_func)neuralnet_evaluator_new, .args = &((char*[])"contact.weights", "contact", "contact") ,
          [4] =  .construct = (new_func)neuralnet_evaluator_new, .args = &((char*[])"crashed.weights", "crashed", "contact") ,
          // The following line is added by a __VA_ARGS__, hence overriding the [3] above.
          [3] =  .construct = (new_func)neuralnet_evaluator_new, .args = &((char*[])"td1228.weights", "contact", "contact") ,
        
    ;

    char **args = (char**) myeval.config[3].args; 
    printf("Neural network weights read from '%s'.\n", args[0]);

    return 0;

我相信这是合法的 C99 (?),但是当我使用 GCC (4.9.2 20141224) 编译时,我收到以下警告:

$ gcc -Wall -Wextra -Wno-override-init -c evaltest.c
evaltest.c: In function ‘main’:
evaltest.c:63:13: warning: initialized field with side-effects overwritten
         [3] =  .construct = (new_func)neuralnet_evaluator_new, .args = &((char*[])"td1228.weights", "contact", "contact") ,
         ^
evaltest.c:63:13: warning: (near initialization for ‘myeval.config[3]’)

但是,当我用 clang 编译时,像这样:

clang -Wall -Wextra -Wno-initializer-overrides -c evaltest.c

我完全没有收到任何警告!然而,两个编译器似乎都构建了预期的代码。

所以,clang,我认为这是可以的代码。有人可以解释为什么 GCC 向我发送此警告吗?警告有效吗?我可以以任何方式压制它吗?还是 GCC 的错误?

【问题讨论】:

【参考方案1】:

因为这里

[3] = .construct = (new_func)neuralnet_evaluator_new, .args = &amp;((char*[])"td1228.weights", "contact", "contact")

你两次初始化.config[3]

Gcc 4.9 Doc: Designated-Init

如果同一个字段被多次初始化,它具有上次初始化的值。如果任何此类重写的初始化具有副作用,则未指定副作用是否发生。目前,GCC 会丢弃它们并发出警告。

【讨论】:

有什么副作用? 感谢您提供指向文档的指针,Simon。有意初始化 config[3] 两次。但是,我不确定我是否熟悉“副作用”这个术语。谁能解释一下什么是副作用,以及为什么这个初始化有副作用? 这里有更多关于这个词的信息:programmers.stackexchange.com/questions/40297/… 但是我不太确定这个初始化的副作用 这里似乎没有任何副作用,所以我怀疑这是一个 gcc 错误。快速搜索 clang 源代码表明它在引用的 gcc 文档中描述的情况下也会产生警告,因此没有看到警告的事实倾向于支持警告是错误的结论。

以上是关于初始化复杂结构,GCC 警告:已覆盖副作用的初始化字段的主要内容,如果未能解决你的问题,请参考以下文章

在特定变量上禁用 GCC“可能未初始化”

gcc 的扩展初始化程序列出警告

忽略 GCC“错误:标量初始化器类型的大括号”错误。让他们警告

为啥使用字符串初始化没有 const 的数组时 gcc 不给出警告?

gcc编译选项-Wall(编译警告:未使用变量变量未初始化类型转换等)

C结构初始化? [复制]