У меня есть проект, состоящий из группы динамически загружаемых модулей. Первоначально все всегда создавалось с помощью MSVC 2003, но в последнее время я работал над тем, чтобы заставить его работать с GCC. Все идет довольно гладко, за исключением одной проблемы. Для 64-битного кода GCC и MSVC не согласны с тем, что такое va_list
. Для 32-битной версии все в порядке. Проблема 64-битного несоответствия возникает, когда модуль, созданный с помощью одного компилятора, имеет публичную функцию с параметром va_list
, и эта функция вызывается из модуля, созданного другим компилятором.
В спецификации говорится ничего о том, что такое va_list
, за пределами раздела 7.15. Переменные аргументы
, параграф 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;
}