2016-07-21 2 views
1

Я использую следующую функцию в течение некоторого времени:функция VARIADIC работает в Win32, но не в Win64

void AddRow(int iNumOfColumns,...) 
{ 
    int* pValuePerColumn = (int*)&iNumOfColumns+1; 

    for (int i=0; i<iNumOfColumns; i++) 
    { 
     // Do something with pValuePerColumn[i] 
    } 
} 

Теперь выясняется, что он выходит из строя на Win64 для одного из наших клиентов.

не имеют 64-битную платформу под рукой, но я предполагаю, что причина:

При вызове функции, аргументы помещаются в стек в виде 64-битных значений.

В этом предположении, я считаю, что замена int* на size_t* должна помочь решить эту проблему.


Мои вопросы:

  • Является ли мой анализ правильно?
  • Правильно ли мое решение?
  • Есть ли более «обычный» способ решения этого?
+3

Вы знакомы с stdarg.h? – 2501

+1

@ 2501: Да, я предполагаю, что вы подразумеваете использование 'va_list' и' va_args'? –

+0

Вы должны использовать va_args для переносимости. Для получения дополнительной информации см. [Соглашение о вызовах Microsoft x86] (https://en.wikipedia.org/wiki/X86_calling_conventions#Microsoft_x64_calling_convention). В любом случае, используя stdarg.h, ваш компилятор позаботится об этом. –

ответ

5

Derefencing указатель на один за последний элемент массива, или пассивного массив объектов, не определенно поведение:

int* pValuePerColumn = (int*)&iNumOfColumns+1; 
... 
pValuePerColumn[i] 

Изменения типа в size_t не имеет никакого отношения к этой проблеме.

Единственный правильный способ использования переменных аргументов - это макросы, предоставленные в stdarg.h.

+0

Спасибо. Пример того, как итерации аргументов, сделает ответ идеальным (хотя я в порядке без него). –

+0

BTW, «Дефрагментация указателя на одно прошлое последнего элемента ... является UB». Разве это не означает, что 'stdarg.h'? Или это проблема, зависящая от платформы, поскольку языковой стандарт не определяет, как аргументы функции вставляются в стек (другими словами, это уникальная версия 'stdarg.h', предоставляемая вместе с каждым компилятором)? –

+0

@barakmanos Это реализовано по-разному для каждой архитектуры. – 2501

3

Вы должны использовать varargs для доступа к дополнительным параметрам в переносном режиме. Ищите va_list документы. Возможно, ваш код должен выглядеть следующий

void AddRow(int iNumOfColumns,...) 
{ 
    va_list ap; 

    va_start(ap, iNumOfColumns); 
    for (int i=0; i<iNumOfColumns; i++) 
    { 
     int col = va_arg(ap, int); 
     // Do something with col 
    } 

    va_end(ap); 
} 

И как я помню на Win64 первые четыре целочисленных арги передаются через регистры, а не через стек, поэтому трюки с указателями не будут работать.

+0

Где в моем вопросе вы видели использование 'varargs'? –

+0

Хорошо, спасибо за пример кодирования. Вероятно, вы должны удалить заявление об открытии, так как я не упоминал 'varargs' нигде в моем вопросе. –

+0

@barakmanos В заголовке есть «Variadic function», не так ли? И похоже, что ваш код пытается использовать аргументы, переданные после 'iNumOfColumns'. – Sergio

Смежные вопросы