可变函数的问题

时间:2010-05-28 00:45:07

标签: c gcc ubuntu variadic-functions

我正在维护一些遗留代码中的以下函数。

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);

当代码执行首次到达此行时,变量'start'和'ms1'具有有效值。

3 个答案:

答案 0 :(得分: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++)
    { 
        ...
    }
    ...
}

答案 1 :(得分: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来阐明...的含义,但由于它干扰了varargs的操作,因此您需要对其进行评论。

答案 2 :(得分:0)

va_start在变量参数开始之前接受va_list参数和最后一个参数。您可以调用va_arg来获取在va_start中指定的参数之后的第一个参数,或者在上一次调用va_arg之后的下一个参数。在你的情况下,你告诉它s1va_start(marker, s1)的可变参数之前的最后一个参数,所以当你调用va_arg时,它会尝试得到 4th < / em>函数调用的参数,但没有第4个,所以你得到了一些奇怪的行为。

您过早地调用va_arg因为如果为1参数提供count,它仍将进入循环,即使您没有足够的参数。你应该使用:

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

但是,如果这样做,则永远不会使用值s1。与Karmastan的答案一起去。