GCC优化器未初始化警告
我用C实现了一个树,现在我想定义一个包装树集。我的树在树中有一个迭代器。h: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
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”无论如何都将是一个完整的字节