gcov и switch операторов - PullRequest
       14

gcov и switch операторов

12 голосов
/ 11 мая 2010

Я запускаю gcov над кодом C с оператором switch. Я написал тестовые случаи, чтобы охватить все возможные пути в этом операторе switch, но он по-прежнему сообщает, что ветвь в операторе switch не принята и менее 100% в статистике «Взять хотя бы раз».

Вот пример кода для демонстрации:

#include "stdio.h"

void foo(int i)
{
    switch(i)
    {
        case 1:printf("a\n");break;
        case 2:printf("b\n");break;
        case 3:printf("c\n");break;
        default: printf("other\n");
    }
}

int main()
{
    int i;
    for(i=0;i<4;++i)
        foo(i);
    return 0;
}

Я собрал "gcc temp.c -fprofile-arcs -ftest-coverage", запустил "a", затем сделал "gcov -b -c temp.c". Выход показывает восемь ветвей на коммутаторе и одна (ветвь 6) не занята.

Что это за ветки и как мне получить 100% покрытие?

Ответы [ 4 ]

4 голосов
/ 13 мая 2010

Ого! Дамп сборки bde показывает, что эта версия GCC компилирует этот оператор switch как некоторое приближение двоичного дерева, начиная с середины набора. Таким образом, он проверяет, равен ли i 2, затем проверяет, больше или меньше 2, а затем для каждой стороны проверяет, равен ли он соответственно 1 или 3, а если нет, то переходит к значению по умолчанию.

Это означает, что для получения результата по умолчанию существует два различных пути кода: один для чисел, превышающих 2, которые не равны 3, и один для чисел, меньших 2, которые не равны 1.

Похоже, вы получите 100% покрытие, если вы измените значение i<4 в цикле на i<=4, чтобы проверить путь с каждой стороны.

(И, да, это то, что очень вероятно изменилось с GCC 3.x на GCC 4.x. Я бы не сказал, что это «исправлено», так как это не «неправильно», если не считать результатов gcov. сбивает с толку. Просто на современном процессоре с предсказанием ветвления он, вероятно, медленный и слишком сложный.)

2 голосов
/ 11 мая 2010

Я получаю тот же результат, используя gcc / gcov 3.4.6.

Для оператора switch он обычно должен генерировать две ветви для каждого оператора case. Один из них, если дело истинно и должно быть выполнено, а другое - это ветвь «падения», которая переходит к следующему делу.

В вашей ситуации похоже, что gcc делает "ветвь" ветвления для последнего случая, что не имеет смысла, так как нечего попадать.

Вот выдержка из кода сборки, сгенерированного gcc (я изменил некоторые метки для удобства чтения):

    cmpl    $2, -4(%ebp)
    je  CASE2
    cmpl    $2, -4(%ebp)
    jg  L7
    cmpl    $1, -4(%ebp)
    je  CASE1
    addl    $1, LPBX1+16
    adcl    $0, LPBX1+20
    jmp DEFAULT
L7:
    cmpl    $3, -4(%ebp)
    je  CASE3
    addl    $1, LPBX1+32
    adcl    $0, LPBX1+36
    jmp DEFAULT

Я признаю, что я не очень разбираюсь в сборке x86 и не понимаю, как использовать метку L7, но она может иметь отношение к дополнительной ветке. Может быть, кто-то с большим знанием о gcc может объяснить, что здесь происходит.

Похоже, что это может быть проблемой со старой версией gcc / gcov, обновление до более новой версии gcc / gcov может решить эту проблему, особенно если учесть другой пост, где результаты выглядят корректно.

1 голос
/ 11 мая 2010

Вы уверены, что используете a.out? Вот мои результаты (gcc 4.4.1):

File 't.c'
Lines executed:100.00% of 11
Branches executed:100.00% of 6
Taken at least once:100.00% of 6
Calls executed:100.00% of 5
t.c:creating 't.c.gcov'
0 голосов
/ 08 октября 2010

Я использую mingw на windows (который не является последним gcc), и похоже, что это может быть отсортировано в более новых версиях gcc.

...