Mam projekt składający się z pęczek dynamicznie ładowanych modułów. Początkowo wszystko było zawsze budowane z MSVC 2003, ale ostatnio pracuję nad tym, żeby to działało z GCC. Wszystko szło całkiem sprawnie, z wyjątkiem jednego problemu. W przypadku kodu 64-bitowego GCC i MSVC nie zgadzają się co do tego, czym jest va_list
. W przypadku wersji 32-bitowych wszystko wygląda dobrze. Problem związany z niedopasowaniem 64-bitowym ma miejsce, gdy moduł zbudowany z jednym kompilatorem ma funkcję publiczną z parametrem va_list
i ta funkcja jest wywoływana z modułu zbudowanego przez inny kompilator.Dopasowywanie typów va_list między kompilatorami
Spec mówi nic o tym, co va_list
jest poza Rozdział 7.15 zmiennych argumentów <stdarg.h>
ustęp 3:
typ zgłoszony jest
va_list
co jest typ obiektu odpowiedni do przechowywania informacji wymaganych przez makra
va_start
,va_arg
,va_end
iva_copy
.
To właśnie oznacza paragraf to wszystko zależny rzeczy kompilator - tak, czy istnieje sposób, aby te dwa kompilatory uzgodnić zawartości 64-bit va_list
? Najmniejszy wpływ na mój system, sprawiając, że GCC pasuje do MSVC va_list
, byłoby najlepsze, ale podejmiemy każde możliwe rozwiązanie.
Dzięki za pomoc!
Edit:
Zrobiłem kilka testów 32-bitowego, a ja mam problemy tam też, która mnie zaskoczyła, ponieważ istnieją podobno ma różnic pomiędzy dowolnymi ABI 32-bitowych platform Intela. Kodzie MSVC używam definiuje wszystkie o zmiennej liczbie argumentów makr funkcyjnych jak:
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)
uprościłem nieco od realnego projektu, ale jest to kod używałem dla mojego testu. W GCC ten kod zdecydowanie nie poprawnie pobiera moje argumenty. Może to tylko błąd, jak sugeruje Zack poniżej?
Edycja ponownie:
dostaję wyniki pracy na kolejny 32-bitowych aplikacji testowej z -O0
, -O0
i -O2
, lecz nie -O3
, -Os
i -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;
}
Uh. Skopiowałeś definicje 'va_ *' z '' z pliku MSVC do pliku, który następnie skompilowałeś z GCC, czy tak jest? Ponieważ to na pewno nie zadziała i nie powie nic pożytecznym. Musisz bezwzględnie użyć GCC '' aby zdefiniować funkcje variadyczne skompilowane przy pomocy GCC (i MSVC dla MSVC) lub twój kod * zostanie * skompilowany. –
zwol
To, co musisz zrobić dla tego testu, to przenieść 'f' do własnego pliku, zamienić wszystkie definicje rąk' va_ * 'na' #include ', wstaw" 'extern int f (int n, ...) ; '' above 'main' w tym pliku, skompiluj jeden z GCC, a drugi z MSVC i połącz oba pliki obiektów. * To * powinno działać w obu kierunkach (wywołania MSVC GCC lub GCC wywołuje MSVC) na x32 lub x64. –
zwol
Tak, to działało dobrze podczas wyłączania wprowadzania lub umieszczania go w oddzielnej jednostce kompilacji.Tak w każdym razie jest to całkowicie oddzielny problem od niedopasowanych typów va_list, co jak mówisz, jest błędem z kompilatorem –