2010-05-11 138 views
12

我正在用switch語句在一些C代碼上運行gcov。我已經編寫了測試用例來覆蓋通過switch語句的每條可能路徑,但它仍然在switch語句中報告沒有采用的分支,並且在「採取至少一次」狀態下報告的分支不到100%。gcov和switch語句

下面是一些示例代碼來演示:

#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%的覆蓋率?

+0

.gcda文件的內容是否有幫助? – Cascabel 2010-05-11 19:52:35

回答

0

我在windows上使用mingw(這不是最新的gcc),它看起來像這樣整理出更新版本的gcc。

1

您確定您正在運行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

他說'跑'一個'',這對我來說建議他跑'a.exe'並使用windows。 – nategoose 2010-05-11 19:40:16

+0

我想 - 默認情況下,我把gcc和unix聯繫起來。結果看起來與偶然運行不同版本的可執行文件一致。 – ergosys 2010-05-11 20:01:48

+0

是的,我在Windows上使用MinGW,這是gcc 3.4.5。這可能是在更新版本的gcc中修復的嗎? – Matt 2010-05-12 14:58:00

2

我使用gcc/gcov 3.4.6得到相同的結果。

對於switch語句,通常應該爲每個case語句生成兩個分支。一個是如果案件是真實的並且應該被執行,另一個是「下落」分支繼續下一個案件。

在你的情況下,它看起來像海灣合作委員會正在爲最後一種情況做一個「fallthrough」分支,這是沒有意義的,因爲沒有什麼可以陷入。

這裏是由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可能會解決問題,尤其是考慮到結果看起來正確的其他帖子。

+0

我懷疑這是gcov做一個貫穿分支;它看起來更可能是gcc這樣做。如果你打開優化會發生什麼? – 2010-05-12 04:23:14

+0

爲了避免執行特定於'default'的代碼,在'default'後面可能有一個'case'是沒有問題的。由於沒有任何東西可以進入,所以最後一個轉換語句的轉換有什麼不妥。 – 2010-05-12 12:24:33

+0

@Brooks打開優化不會改變問題,看起來好像我使用-O3或更高版本,它會添加更多的分支。 – WildCrustacean 2010-05-12 13:43:29

4

Oho! bde的程序集轉儲顯示該版本的GCC正在將此開關語句編譯爲二叉樹的一些近似值,從該集的中間開始。因此它會檢查i是否等於2,然後檢查它是大於還是小於2,然後對於每一邊它檢查它是否分別等於1或3,如果不相等,則它將進入默認值。

這意味着有兩個不同的代碼路徑它到達默認結果 - 一個用於不屬於3個數字大於2,和一個爲不是1.

數低於2

如果您將循環中的i<4更改爲i<=4,以便測試每邊的路徑,看起來您會達到100%的覆蓋率。

(而且,是的,這很可能已經從GCC 3.x變成了GCC 4.x.我不會說它是「固定的」,因爲除了製作gcov之外它不是「錯誤的」結果令人困惑,只是在具有分支預測的現代處理器上,它可能很慢並且過於複雜。)