va_list Fehlverhalten unter Linux

8

Ich habe einen Code, der variadische Parameter in va_list umwandelt und dann die Liste an eine Funktion weiterleitet, die dann vsnprintf aufruft. Dies funktioniert gut unter Windows und OS X, aber es schlägt mit seltsamen Ergebnissen unter Linux fehl.

Im folgenden Codebeispiel:

%Vor%

Die Ausgabe des zweiten Aufrufs vsnprintf ist 17 und das Ergebnis von strcmp ist 31; aber ich verstehe nicht, warum vsnprintf 17 zurückgibt, da This is a test. 15 Zeichen ist, addiere NULL und du erhältst 16.

Verwandte Themen, die ich gesehen habe, aber das Thema nicht behandeln:

Mit @ Mat's Antwort (ich verwende das va_list -Objekt, was nicht erlaubt ist), kommt es direkt zum ersten verwandten Thread, mit dem ich verlinkt bin. Also habe ich stattdessen diesen Code versucht:

%Vor%

Welche, gemäß der C99 Spezifikation (Fußnote in Abschnitt 7.15 ), sollte funktionieren:

  

Es ist erlaubt, einen Zeiger auf eine va_list zu erstellen und diesen Zeiger zu übergeben   zu einer anderen Funktion, in diesem Fall kann die ursprüngliche Funktion machen   Weitere Verwendung der ursprünglichen Liste nach der anderen Funktion zurück.

Aber mein Compiler (gcc 4.4.5 im C99-Modus) gibt mir diesen Fehler bezüglich der ersten Zeile von myPrintfInner :

%Vor%

Und die resultierende binäre erzeugt genau den gleichen Effekt wie beim ersten Mal.

Folgendes gefunden: Greift GCC einen Zeiger auf eine va_list, die an eine Funktion übergeben wurde, falsch?

Die vorgeschlagene Problemumgehung (die nicht garantiert funktionierte, aber in der Praxis funktionierte), ist die Verwendung von arg_copy first:

%Vor%     
Mahmoud Al-Qudsi 30.03.2012, 05:37
quelle

2 Antworten

11

Wie Sie wissen, besteht das Problem darin, dass Sie va_list wiederverwenden. Wenn Sie Ihren Code nicht wie vorgeschlagen umstrukturieren möchten, können Sie das Makro C99 va_copy() verwenden. so:

%Vor%

Auf Compilern, die C99 nicht unterstützen, können Sie stattdessen __va_copy() oder verwenden Definieren Sie Ihre eigene va_copy() -Implementierung (die nicht portierbar ist, aber Sie können Compiler- / Plattform-Sniffing immer in einer Header-Datei verwenden, wenn Sie dies wirklich brauchen). Aber wirklich, es ist 13 Jahre her - jeder ordentliche Compiler sollte C99 in diesen Tagen unterstützen, zumindest wenn man ihm die richtigen Optionen gibt ( -std=c99 für GCC).

    
Ilmari Karonen 30.03.2012, 06:06
quelle
7

Das Problem ist, dass Sie (abgesehen von der fehlenden return-Anweisung) den Parameter va_list erneut verwenden, ohne ihn zurückzusetzen. Das ist nicht gut.

Versuchen Sie etwas wie:

%Vor%

(Und schalten Sie die Warnungen Ihres Compilers ein.)

Ich glaube nicht, dass die Fußnote, auf die Sie verweisen, das bedeutet, was Sie denken. Ich lese es als: Wenn Sie ein va_list direkt übergeben (als Wert, nicht als Zeiger), ist das einzige, was Sie im Aufrufer tun können, va_end it. Aber wenn Sie es als Zeiger übergeben, könnten Sie zum Beispiel va_arg im Aufrufer aufrufen, wenn der Aufgerufene nicht alle va_list "verbraucht" hat.

Du könntest es aber mit va_copy versuchen. Etwas wie:

%Vor%     
Mat 30.03.2012 05:45
quelle

Tags und Links