Проблемы с вариадической функцией - PullRequest
0 голосов
/ 28 мая 2010

У меня есть следующая функция из некоторого устаревшего кода, который я поддерживаю.

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. Код скомпилирован и работает без сбоев в Windows XP, когда я скомпилировал его с использованием VS2005. Теперь я переместил код в Ubuntu Karmic, и у меня возникли проблемы с более строгим компилятором в Linux. Кто-нибудь может определить причину неправильного чтения параметра в выражении var_arg ()?

Я компилирую с использованием gcc версии 4.4.1

Редактировать

Утверждение, вызывающее SEGV, таково:

start = getMaxStart(start, 1, ms1);

Переменные 'start' и 'ms1' имеют допустимые значения, когда выполнение кода впервые достигает этой строки.

Ответы [ 3 ]

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

Как написано, когда вы передаете только один 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 голос
/ 28 мая 2010

Немного подозрительно, что 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, его необходимо закомментировать.

0 голосов
/ 28 мая 2010

va_start принимает аргумент va_list и последний аргумент непосредственно перед началом аргументов переменной. Вы вызываете va_arg, чтобы получить первый аргумент после того, который вы указали в va_start, или следующий аргумент после предыдущего вызова va_arg. В вашем случае вы сказали, что s1 - это последний аргумент перед аргументами с переменным значением va_start(marker, s1), поэтому при вызове va_arg он попытается получить аргумент 4th для вашей функции звоните, но 4-го номера нет, поэтому вы получаете странное поведение.

Вы вызываете va_arg преждевременно, потому что если вы введете 1 для аргумента count, он все равно войдет в цикл, даже если у вас там недостаточно аргументов. Вы должны использовать:

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

Но, если вы сделаете это, значение s1 никогда не будет использовано. Иди с ответом Кармастана.

...