У меня есть проект, состоящий из набора динамически загружаемых модулей. Первоначально все всегда собиралось с помощью MSVC 2003, но в последнее время я работаю над тем, чтобы заставить его работать с GCC. Все прошло довольно гладко, за исключением одной проблемы. Для 64-битного кода GCC и MSVC не согласны с тем, что такое va_list
. Для 32-битной все выглядит нормально. Проблема, вызванная 64-битным несоответствием, заключается в том, что модуль, созданный одним компилятором, имеет общедоступную функцию с параметром va_list
, и эта функция вызывается из модуля, созданного другим компилятором.
Спецификация ничего не говорит о том, что такое va_list
, кроме Раздел 7.15 Переменные аргументы <stdarg.h>
, параграф 3:
Объявленный тип
va_list
который является типом объекта, подходящим для хранения информации, необходимой для макросов
va_start
,va_arg
,va_end
иva_copy
.
Этот абзац просто означает, что все это зависит от компилятора - так есть ли способ заставить эти два компилятора согласовать содержимое 64-битного va_list
? Для наименьшего воздействия на мою систему лучше всего сделать так, чтобы GCC соответствовал MSVC va_list
, но я приму любое решение, которое смогу найти.
Спасибо за помощь!
Редактировать:
Я провел некоторое 32-битное тестирование, и у меня тоже есть проблемы, что меня удивило, так как якобы нет различий в ABI между любыми 32-битными платформами Intel. Кодовая база MSVC, которую я использую, определяет все макросы функций с переменным числом переменных следующим образом:
typedef char *va_list;
#define intsizeof(n) ((sizeof(n) + sizeof(int) - 1) &~(sizeof(int) - 1))
#define va_start(ap, v) (ap = (va_list)&(v) + intsizeof(v))
#define va_arg(ap, t) (*(t *) ((ap += intsizeof(t)) - intsizeof(t)))
#define va_end(ap) (ap = (va_list)0)
Я немного упростил реальный проект, но это код, который я использовал для своего теста. С GCC этот код определенно неправильно получает мои аргументы. Может быть, это просто ошибка, как предполагает Зак ниже?
Редактировать снова:
Я получаю рабочие результаты для следующего 32-битного тестового приложения с -O0
, -O0
и -O2
, но не с -O3
, -Os
и -Oz
:
typedef char *va_list;
#define intsizeof(n) ((sizeof(n) + sizeof(int) - 1) &~(sizeof(int) - 1))
#define va_start(ap, v) (ap = (va_list)&(v) + intsizeof(v))
#define va_arg(ap, t) (*(t *) ((ap += intsizeof(t)) - intsizeof(t)))
#define va_end(ap) (ap = (va_list)0)
int printf(const char *format, ...);
int f(int n, ...)
{
int r = 0;
va_list ap;
va_start(ap, n);
while (n--)
r = va_arg(ap, int);
va_end(ap);
return r;
}
int main(int argc, char **argv)
{
int r;
r = f(1, 1, 2, 3, 4, 5);
printf("%x\n", r);
r = f(2, 1, 2, 3, 4, 5);
printf("%x\n", r);
r = f(3, 1, 2, 3, 4, 5);
printf("%x\n", r);
r = f(4, 1, 2, 3, 4, 5);
printf("%x\n", r);
r = f(5, 1, 2, 3, 4, 5);
printf("%x\n", r);
return 0;
}
va_*
из<stdarg.h>
MSVC в файл, который затем скомпилировали с помощью GCC, не так ли? Потому что это точно не сработает и ничего полезного вам не скажет. Вы обязательно должны использовать<stdarg.h>
GCC для определения функций с переменным числом аргументов, скомпилированных с помощью GCC (и MSVC для MSVC), иначе ваш код будет скомпилирован неправильно. - person zwol   schedule 30.09.2010f
в его собственный файл, заменить все определения рукva_*
на#include <stdarg.h>
, поместитьextern int f(int n, ...);
вышеmain
в этом файле, скомпилировать один с помощью GCC, а другой с помощью MSVC и связать два объектных файла. . Это должно работать в любом направлении (MSVC вызывает GCC или GCC вызывает MSVC) либо на x32, либо на x64. - person zwol   schedule 30.09.2010