2010-05-28 91 views
0

我從我正在維護的一些遺留代碼中獲得以下函數。可變參數函數的問題

long getMaxStart(long start, long count, const myStruct *s1, ...) 
{ 
    long  i1, maxstart; 
    myStruct *s2; 
    va_list marker; 

    maxstart = start; 

    /*BUGFIX: 003 */ 
    /*(va_start(marker, count);*/ 
    va_start(marker, s1); 

    for (i1 = 1; i1 <= count; i1++) 
    { 
     s2 = va_arg(marker, myStruct *);   /* <- s2 is assigned null here */ 
     maxstart = MAX(maxstart, s2->firstvalid); /* <- SEGV here */ 
    } 

    va_end(marker); 
    return (maxstart); 
} 

當只用一個myStruct參數調用該函數時,它會導致一個SEGV。當我使用VS2005編譯代碼時,代碼編譯並運行時不會在Windows XP上崩潰。我現在已經將代碼移到了Ubuntu Karmic中,而且我在Linux上的更嚴格的編譯器時遇到了問題。是否有人能夠發現是什麼導致參數不能在var_arg()語句中正確讀取?

我使用gcc版本編譯4.4.1

編輯

引起SEGV聲明是這樣的一個:

start = getMaxStart(start, 1, ms1); 

變量 '開始' 和 'MS1'代碼執行第一次到達這一行時有有效的值。

+2

你調用它的代碼是什麼樣的? – 2010-05-28 00:47:57

回答

4

正如你所寫,當你只傳遞一個myStruct參數時,s1被綁定到該參數並且你的va_list將是空的。然後,你在循環中做的第一件事就是從空列表中獲取參數,因此是NULL。

如果你需要至少一個參數,並希望編譯器類型檢查你,你不得不做這樣的事情:

long getMaxStart(long start, long count, const myStruct *s1, ...) { 
    ... 
    va_start(marker, s1); 
    maxstart = s1->firstvalid; /* actually use s1 this time! */ 
    for (i1 = 1; i1 < count; i1++) /* different from your code */ 
    { 
     ... 
    } 
    ... 
} 

否則,你最好只刪除s1從像Potatoswatter函數定義中提到:

long getMaxStart(long start, long count, ...) { 
    ... 
    va_start(marker, count); /* not a bug */ 
    maxstart = -1; /* pick something resonable for your app */ 
    for (i1 = 0; i1 < count; i1++) 
    { 
     ... 
    } 
    ... 
} 
+0

@ karnastan:+1爲清晰的解釋 – morpheous 2010-05-28 08:19:49

1

s1未被使用有點可疑。 count是否包含s1,即傳入的指針總數?也許你想消除s1並使用va_start(marker, count)

編輯:鑑於澄清的意見,解決辦法是肯定

long getMaxStart(long start, long count, /* const myStruct *s1, */ ...) 
{ 
    long  i1, maxstart; 
    myStruct *s2; 
    va_list marker; 

    maxstart = start; 

    va_start(marker, count); 

    for (i1 = 1; i1 <= count; i1++) 
    { 
     s2 = va_arg(marker, myStruct *); 
     maxstart = MAX(maxstart, s2->firstvalid); 
    } 

    va_end(marker); 
    return (maxstart); 
} 

遺留代碼中使用s1澄清什麼...意思,但因爲它與可變參數的操作干擾,你需要註釋掉。

+0

使用s1 - 它是函數定義中的第5條語句。 – morpheous 2010-05-28 01:13:54

+0

舊的代碼確實使用了va_start(marker,count) - 你可以看到它已被修改(註釋掉)。編譯器被警告大意,va_start()宏的第二個參數不是已知列表中的最後一項 - 我對此進行了更正。 – morpheous 2010-05-28 01:15:59

+0

@morpheous:'s1'被'va_start'用作佔位符,但其內容被丟棄。通過擦除s1的聲明來消除編譯器的警告,而不是將它傳遞給'va_start'。 – Potatoswatter 2010-05-28 01:45:08

0

va_start需要va_list參數和可變參數開始之前的最後一個參數。您可以撥打va_arg以獲得第一個參數,即在va_start中指定的參數之後,或者先前調用va_arg之後的下一個參數。在你的情況下,你已經告訴它s1va_start(marker, s1)的可變參數前的最後一個參數,所以當你調用va_arg時,它會嘗試獲得一個參數給你的函數調用,但是沒有第四個,所以你得到一些奇怪的行爲。

您提前調用va_arg是因爲如果您爲count參數提供1參數,它仍會進入循環,即使您沒有足夠的參數。您應該使用:

for (i1 = 1; i1 < count; i1++) 

但是,如果您這樣做,則從不使用值s1。跟着Karmastan的回答。