I implemented a tree in C, and I now want to define a wrapper tree set. I have an iterator for my tree in tree.h:
typedef struct tree_iter_t {
void *current;
tree_t *tree;
unsigned char info : 2;
} tree_iter_t;
and a function to get an iterator in 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;
}
I can compile this with -Wall -O2 with no warnings. For my tree set, I defined my tree set iterator in tset.h as follows:
typedef struct tset_t tset_t;
typedef struct tset_iter_t {
tree_iter_t iter;
} tset_iter_t;
and a function to obtain it in 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;
}
When I compile with gcc -Wall -c -combine tset.c tree.c, I have no problems, but when I add -O2, I get a warning on the return statement: warning: ‘it.iter.tree’ is used uninitialized in this function. Why does GCC have a problem with this? Am I missing something obvious? It looks initialized to me. I ran gcc -S -O2 tset.c to try to get a sense of what was going on, GCC gave no warning and produced this:
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
I know optimization can generate some strange-looking code, but what the heck is going on here!? All of my other (optimized) wrapper functions are 10-ish lines of assembly (just the usual function call overhead for calling tree’s functions). gcc -O2 -S -combine tset.c tree.c gave me the warning, inlined titerator, and produced this:
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
When I changed the implementation to:
tset_iter_t tsiterator(tset_t *ts) {
tset_iter_t it;
tree_iter_t i = titerator(ts->tree);
it.iter = i;
return it;
}
it had no problems. What is GCC optimizing (or analyzing) in the first case, and why is it giving me a warning?
Thanks.
I think the warning is a bug. Which gcc are you using? Doesn’t happen for me when I compile (admittedly a single file) with gcc 4.0 and 4.2.
Here is an annotated version of the optimised assembler. I can’t see anything unassigned here, which is why I think the warning is not right. I’ve guessed about the tree structure.
EDIT: Note that the compiler carefully preserves the upper 6 bits of random uninitialized junk in
tree_iter_t.info.