GCC优化器未初始化警告

GCC优化器未初始化警告,c,gcc,compiler-warnings,compiler-optimization,C,Gcc,Compiler Warnings,Compiler Optimization,我用C实现了一个树,现在我想定义一个包装树集。我的树在树中有一个迭代器。h: typedef struct tree_iter_t { void *current; tree_t *tree; unsigned char info : 2; } tree_iter_t; 以及一个在tree.c中获取迭代器的函数: tree_iter_t titerator(tree_t *t) { tree_iter_t it; it.current = t->m

我用C实现了一个树,现在我想定义一个包装树集。我的树在树中有一个迭代器。h:

typedef struct tree_iter_t {
    void *current;
    tree_t *tree;
    unsigned char info : 2;
} tree_iter_t;
以及一个在tree.c中获取迭代器的函数:

tree_iter_t titerator(tree_t *t) {
    tree_iter_t it;
    it.current = t->min;
    if (t->min) it.info = 0;
    else it.info = 3;
    it.tree = t;
    return it;
}
我可以用
-Wall-O2
编译这个,而不需要任何警告。对于我的树集,我在tset.h中定义了树集迭代器,如下所示:

typedef struct tset_t tset_t;

typedef struct tset_iter_t {
    tree_iter_t iter;
} tset_iter_t;
以及在tset.c中获取它的函数

struct tset_t {
    tree_t *tree;
};

tset_iter_t tsiterator(tset_t *ts) {
    tset_iter_t it;
    it.iter = titerator(ts->tree);
    return it;
}
当我使用
gcc-Wall-c-combine-tset.c tree.c
编译时,我没有问题,但是当我添加
-O2
时,我在返回语句上得到一个警告:
警告:“it.iter.tree”在这个函数中未初始化使用。为什么GCC对此有问题?我错过了什么明显的东西吗?在我看来,这是一件好事。我运行了
gcc-S-o2tset.c
试图了解发生了什么,gcc没有给出任何警告,并生成了以下内容:

tsiterator:
pushl   %ebp
movl    %esp, %ebp
pushl   %ebx
subl    $36, %esp
movl    12(%ebp), %edx
movl    8(%ebp), %ebx
leal    -20(%ebp), %eax
movl    (%edx), %edx
movl    %eax, (%esp)
movl    %edx, 4(%esp)
call    titerator
movzbl  -12(%ebp), %edx
movzbl  8(%ebx), %eax
andl    $3, %edx
andl    $-4, %eax
orl     %edx, %eax
subl    $4, %esp
movb    %al, 8(%ebx)
movl    -16(%ebp), %eax
movl    %eax, 4(%ebx)
movl    -20(%ebp), %eax
movl    %eax, (%ebx)
movl    %ebx, %eax
movl    -4(%ebp), %ebx
leave
ret $4
tsiterator:
pushl   %ebp
movl    %esp, %ebp
movl    12(%ebp), %edx
pushl   %ebx
movl    8(%ebp), %eax
movl    (%edx), %ecx
movl    4(%ecx), %edx
movl    %ecx, 4(%eax)
cmpl    $1, %edx
movl    %edx, (%eax)
movzbl  8(%eax), %edx
sbbl    %ebx, %ebx
andl    $3, %ebx
andl    $-4, %edx
orl     %ebx, %edx
movb    %dl, 8(%eax)
popl    %ebx
popl    %ebp
ret $4
我知道优化可以生成一些看起来很奇怪的代码,但这到底是怎么回事!?我的所有其他(优化的)包装函数都是10行汇编(只是调用树函数的常见函数调用开销)
gcc-O2-S-combine-tset.c tree.c
给了我警告,内联滴定仪,并产生了以下结果:

tsiterator:
pushl   %ebp
movl    %esp, %ebp
pushl   %ebx
subl    $36, %esp
movl    12(%ebp), %edx
movl    8(%ebp), %ebx
leal    -20(%ebp), %eax
movl    (%edx), %edx
movl    %eax, (%esp)
movl    %edx, 4(%esp)
call    titerator
movzbl  -12(%ebp), %edx
movzbl  8(%ebx), %eax
andl    $3, %edx
andl    $-4, %eax
orl     %edx, %eax
subl    $4, %esp
movb    %al, 8(%ebx)
movl    -16(%ebp), %eax
movl    %eax, 4(%ebx)
movl    -20(%ebp), %eax
movl    %eax, (%ebx)
movl    %ebx, %eax
movl    -4(%ebp), %ebx
leave
ret $4
tsiterator:
pushl   %ebp
movl    %esp, %ebp
movl    12(%ebp), %edx
pushl   %ebx
movl    8(%ebp), %eax
movl    (%edx), %ecx
movl    4(%ecx), %edx
movl    %ecx, 4(%eax)
cmpl    $1, %edx
movl    %edx, (%eax)
movzbl  8(%eax), %edx
sbbl    %ebx, %ebx
andl    $3, %ebx
andl    $-4, %edx
orl     %ebx, %edx
movb    %dl, 8(%eax)
popl    %ebx
popl    %ebp
ret $4
当我将实现更改为:

tset_iter_t tsiterator(tset_t *ts) {
    tset_iter_t it;
    tree_iter_t i = titerator(ts->tree);
    it.iter = i;
    return it;
}
没有问题。在第一种情况下,GCC优化(或分析)是什么?为什么它会给我一个警告


谢谢。

我认为这个警告是个错误。您使用的是哪个gcc?当我使用GCC4.0和4.2编译(承认是一个文件)时,这种情况不会发生

这是优化汇编程序的注释版本。我在这里看不到任何未分配的内容,这就是我认为警告不正确的原因。我猜到了树的结构

tsiterator:
    pushl   %ebp
    movl    %esp, %ebp
    movl    12(%ebp), %edx  ; edx has pointer to ts
    pushl   %ebx
    movl    8(%ebp), %eax   ; eax has pointer to retval
    movl    (%edx), %ecx    ; ecx has ts->tree (?)
    movl    4(%ecx), %edx   ; edx has ts->tree->min (?)
    movl    %ecx, 4(%eax)   ; store ts->tree into retval->iter->tree
    cmpl    $1, %edx    
    movl    %edx, (%eax)    ; store ts->tree->min into retval->iter->current
    ;; This and the cmpl instruction above is all
    ;; handling the bitmasking for retval->iter->info.
    ;; Probably would be more efficient to not use a
    ;; bit mask here, as the compiler could remove the
    ;; second "and" and "or" instructions.
    movzbl  8(%eax), %edx   ; get current value of retval->iter->info
    sbbl    %ebx, %ebx  ; ebx = 0 if unsigned edx < 1, else -1
    andl    $3, %ebx    ; mask off new value            
    andl    $-4, %edx   ; mask off old value   
    orl     %ebx, %edx  ; combine old | new    
    movb    %dl, 8(%eax)    ; store combined into retval->iter->info
    popl    %ebx
    popl    %ebp
    ret $4
t迭代器:
推力%ebp
移动%esp,%ebp
movl 12(%ebp),%edx;edx有指向ts的指针
推送%ebx
movl 8(%ebp),%eax;eax有指向retval的指针
movl(%edx),%ecx;ecx有ts->树(?)
movl 4(%ecx),%edx;edx有ts->tree->min(?)
movl%ecx,4%(eax);将ts->tree存储到retval->iter->tree中
cmpl$1,%edx
移动百分比edx,(%eax);将ts->tree->min存储到retval->iter->current
;; 这和上面的cmpl指令就是全部
;; 处理retval->iter->info的位掩码。
;; 如果不使用
;; 位掩码,因为编译器可以删除
;; 第二个“和”和“或”指示。
movzbl 8(%eax),%edx;获取retval->iter->info的当前值
sbbl%ebx,%ebx;如果无符号edx<1,则ebx=0,否则为-1
andl$3,%ebx;屏蔽新值
andl$-4%,edx;掩盖旧值
orl%ebx,%edx;新旧结合
movb%dl,8%(eax);存储合并到retval->iter->info
popl%ebx
popl%ebp
ret$4

编辑:请注意,编译器在
tree\u iter\t.info

中小心地保留了上面6位的随机未初始化垃圾,我认为这是一个错误。您使用的是哪个gcc?当我使用GCC4.0和4.2编译(承认是一个文件)时,这种情况不会发生

这是优化汇编程序的注释版本。我在这里看不到任何未分配的内容,这就是我认为警告不正确的原因。我猜到了树的结构

tsiterator:
    pushl   %ebp
    movl    %esp, %ebp
    movl    12(%ebp), %edx  ; edx has pointer to ts
    pushl   %ebx
    movl    8(%ebp), %eax   ; eax has pointer to retval
    movl    (%edx), %ecx    ; ecx has ts->tree (?)
    movl    4(%ecx), %edx   ; edx has ts->tree->min (?)
    movl    %ecx, 4(%eax)   ; store ts->tree into retval->iter->tree
    cmpl    $1, %edx    
    movl    %edx, (%eax)    ; store ts->tree->min into retval->iter->current
    ;; This and the cmpl instruction above is all
    ;; handling the bitmasking for retval->iter->info.
    ;; Probably would be more efficient to not use a
    ;; bit mask here, as the compiler could remove the
    ;; second "and" and "or" instructions.
    movzbl  8(%eax), %edx   ; get current value of retval->iter->info
    sbbl    %ebx, %ebx  ; ebx = 0 if unsigned edx < 1, else -1
    andl    $3, %ebx    ; mask off new value            
    andl    $-4, %edx   ; mask off old value   
    orl     %ebx, %edx  ; combine old | new    
    movb    %dl, 8(%eax)    ; store combined into retval->iter->info
    popl    %ebx
    popl    %ebp
    ret $4
t迭代器:
推力%ebp
移动%esp,%ebp
movl 12(%ebp),%edx;edx有指向ts的指针
推送%ebx
movl 8(%ebp),%eax;eax有指向retval的指针
movl(%edx),%ecx;ecx有ts->树(?)
movl 4(%ecx),%edx;edx有ts->tree->min(?)
movl%ecx,4%(eax);将ts->tree存储到retval->iter->tree中
cmpl$1,%edx
移动百分比edx,(%eax);将ts->tree->min存储到retval->iter->current
;; 这和上面的cmpl指令就是全部
;; 处理retval->iter->info的位掩码。
;; 如果不使用
;; 位掩码,因为编译器可以删除
;; 第二个“和”和“或”指示。
movzbl 8(%eax),%edx;获取retval->iter->info的当前值
sbbl%ebx,%ebx;如果无符号edx<1,则ebx=0,否则为-1
andl$3,%ebx;屏蔽新值
andl$-4%,edx;掩盖旧值
orl%ebx,%edx;新旧结合
movb%dl,8%(eax);存储合并到retval->iter->info
popl%ebx
popl%ebp
ret$4

编辑:请注意,编译器在
tree\u iter\t.info

中小心地保留了随机未初始化垃圾的上6位。我不明白gcc为什么会抱怨特定字段
tree
,但他说得对,您从函数返回的结构部分没有初始化。事实上,您应该始终只初始化变量的一个字段,然后使用
0
自动初始化其他字段。在您的情况下,最简单的方法是使用C99指定的初始值设定项:

tree_iter_t it = { .tree = t };

然后,您也可以跳过对该字段的分配。

我不明白为什么gcc可能会抱怨特定的字段
,但他是对的,您从函数返回的结构部分没有初始化。事实上,您应该始终只初始化变量的一个字段,然后使用
0
自动初始化其他字段。在您的情况下,最简单的方法是使用C99指定的初始值设定项:

tree_iter_t it = { .tree = t };

然后,您也可以跳过分配到该字段。

树\u iter\t
然后
it.tree=t。it.tree在哪里?为什么不发布真正的code.nitpick-在树中声明一个位字段“char info:2;”并没有节省任何内存。编译器仍然必须为每个实例分配固定数量的字节,因此“info”无论如何都将是一个完整的字节