2010-05-28 89 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的回答。