Неинициализированное предупреждение с оптимизатором GCC - PullRequest
1 голос
/ 22 октября 2011

Я реализовал дерево в C, и теперь я хочу определить набор деревьев-оболочек.У меня есть итератор для моего дерева в tree.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, я получаю предупреждение о выражении возврата: warning: ‘it.iter.tree’ is used uninitialized in this function.Почему у GCC есть проблема с этим?Я что-то упускаю из виду?Это выглядит инициализированным для меня.Я запустил gcc -S -O2 tset.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

Я знаю, оптимизация может генерировать какой-то странно выглядящий код, но, черт возьми, этоздесь происходит?Все мои другие (оптимизированные) функции-обертки представляют собой 10-ти строчные строки сборки (обычные накладные расходы на вызовы функций для вызова функций дерева).gcc -O2 -S -combine tset.c tree.c дал мне предупреждение, встроенный титратор и произвел это:

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 оптимизирует (или анализирует) в первом случае и почему он дает мне предупреждение?

Спасибо.

Ответы [ 2 ]

1 голос
/ 22 октября 2011

Я думаю, что предупреждение является ошибкой.Какой GCC вы используете?У меня не бывает, когда я компилирую (по общему признанию, один файл) с gcc 4.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

РЕДАКТИРОВАТЬ: обратите внимание, что компилятор тщательно сохраняет верхние 6 бит случайного неинициализированного мусора в tree_iter_t.info.

0 голосов
/ 22 октября 2011

Я не мог понять, почему gcc может жаловаться на это конкретное поле tree, но он прав, что части структуры, которые вы возвращаете из функции, не инициализируются.Фактически, вы должны в основном всегда инициализировать только одно поле вашей переменной, тогда как остальные автоматически инициализируются с помощью 0.В вашем случае проще всего использовать назначенные инициализаторы C99:

tree_iter_t it = { .tree = t };

, а затем вы можете пропустить присвоение этому полю позже.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...