Ich habe ein Projekt, das aus einer Reihe dynamisch geladener Module besteht. Ursprünglich wurde alles mit MSVC 2003 erstellt, aber in letzter Zeit habe ich daran gearbeitet, es mit GCC zu arbeiten. Alles lief ziemlich reibungslos, bis auf ein Problem. Bei 64-Bit-Code stimmen GCC und MSVC nicht überein, was ein va_list
ist. Für 32-Bit scheinen die Dinge in Ordnung zu sein. Das Problem der 64-Bit-Mismatch ist, wenn ein Modul, das mit einem Compiler erstellt wurde, eine öffentliche Funktion mit einem va_list
-Parameter hat und diese Funktion von einem Modul aufgerufen wird, das vom anderen Compiler erstellt wurde.
Die Spezifikation sagt nichts darüber aus, was ein va_list
ist, außerhalb von Abschnitt 7.15 Variable Argumente <stdarg.h>
, Absatz 3:
Der angegebene Typ ist
va_list
Dies ist ein Objekttyp, der die von den Makros benötigten Informationen enthält
va_start
,va_arg
,va_end
undva_copy
.
Dieser Absatz bedeutet nur, dass dies alles Compiler-abhängige Dinge sind - gibt es also eine Möglichkeit, diese beiden Compiler auf den Inhalt eines 64-Bit va_list
abzustimmen? Für die geringste Auswirkung auf mein System wäre GCC am besten mit der MSVC va_list
kompatibel, aber ich nehme jede Lösung, die ich bekommen kann.
Danke, dass Sie mithelfen!
Bearbeiten:
Ich habe einige 32-Bit-Tests gemacht, und ich habe auch Probleme, die mich überrascht haben, da es angeblich keine ABI-Unterschiede zwischen 32-Bit-Intel-Plattformen gibt. Die MSVC-Codebasis, die ich verwende, definiert alle variadischen Funktionsmakros wie folgt:
%Vor%Ich habe ein bisschen vom realen Projekt vereinfacht, aber das ist der Code, den ich für meinen Test verwendet habe. Mit GCC erhält dieser Code meine Argumente definitiv nicht richtig. Vielleicht ist es nur ein Fehler, wie Zack unten vorschlägt?
Nochmals bearbeiten:
Ich erhalte Arbeitsergebnisse für die folgende 32-Bit-Testanwendung mit -O0
, -O0
und -O2
, aber nicht -O3
, -Os
und -Oz
:
Da MSVC den Win64 ABI definiert, haben Sie einen Fehler in GCC gefunden. Bitte melden Sie es in GCC bugzilla .
Da es anscheinend keinen ABI für va_list
gibt (oder zumindest MSVC und GCC nicht mit einem ABI einverstanden sind), müssen Sie diese Parameter wahrscheinlich selbst marshallen.
Die einfachste Möglichkeit, um dieses Problem von oben zu lösen, besteht darin, Ihre variablen Parameter in einem dynamisch zugewiesenen Speicherblock zu verwalten und einen Zeiger auf diesen Block zu übergeben.
Das hat natürlich den Nachteil, dass die Schnittstelle zu den Funktionen, die va_args verwenden, komplett geändert wurde.
Da es keinen Standard gibt, wie va_args gehandhabt werden müssen, sollten Sie Ihre eigene Version wahrscheinlich besser rollen lassen, wenn Sie diese Funktionalität in einer kompilierten Plattform konsistent nutzen möchten. Wir haben dies nicht getan und wurden in letzter Zeit mehrmals gebrannt, als wir zusätzliche Ziele für unsere Codebasis unterstützten. Ich würde gerne falsch liegen, wenn andere eine bessere Lösung haben:)
Versuchen Sie es mit einem Debugger auf Assembly-Ebene wie ollydbg auszuführen, da Ihr Problem möglicherweise nicht mit den va_args zusammenhängt, sondern mit der Art, wie der Compiler die Argumente erwartet (gcc könnte sie im linux-Format erwarten), wo msvc win64 __fastcall verwendet), wird dies der Situation etwas mehr Licht geben. Ein anderer, ziemlich hacky Ansatz ist versuchen, mit den Definitionen für die 64-Bit-Argumente, wie Importieren der MSVC-Makros in den GCC-Header (verwenden Sie eine Projekt lokale Kopie natürlich), sehen, ob das etwas heilt.
Welche Arten verwenden Sie? Streng genommen definiert WinXX nur das Verhalten von Zeichen, Strings, Zeigern und ganzen Zahlen für Varargs ( siehe Dokumentation für wsprintf in user32.dll ). Wenn Sie Fließkommawerte oder Strukturen übergeben, sind die Ergebnisse für die Windows-Plattform technisch nicht spezifiziert.
Tags und Links c gcc variadic-functions visual-studio-2003