Ich habe einige Code, der variadic Parameter in eine va_list
konvertiert, dann übergibt die Liste an eine Funktion, die dann ruft vsnprintf
. Dies funktioniert unter Windows und OS X gut, aber es schlägt mit seltsamen Ergebnissen unter Linux fehl.va_list Fehlverhalten unter Linux
Im folgenden Codebeispiel:
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
char *myPrintfInner(const char *message, va_list params)
{
va_list *original = ¶ms;
size_t length = vsnprintf(NULL, 0, message, *original);
char *final = (char *) malloc((length + 1) * sizeof(char));
int result = vsnprintf(final, length + 1, message, params);
printf("vsnprintf result: %d\r\n", result);
printf("%s\r\n", final);
return final;
}
char *myPrintf(const char *message, ...)
{
va_list va_args;
va_start(va_args, message);
size_t length = vsnprintf(NULL, 0, message, va_args);
char *final = (char *) malloc((length + 1) * sizeof(char));
int result = vsnprintf(final, length + 1, message, va_args);
printf("vsnprintf result: %d\r\n", result);
printf("%s\r\n", final);
va_end(va_args);
return final;
}
int main(int argc, char **argv)
{
char *test = myPrintf("This is a %s.", "test");
char *actual = "This is a test.";
int result = strcmp(test, actual);
if (result != 0)
{
printf("%d: Test failure!\r\n", result);
}
else
{
printf("Test succeeded.\r\n");
}
return 0;
}
Der Ausgang des zweiten vsnprintf
Anruf 17, und das Ergebnis der strcmp
ist 31; aber ich nicht, warum vsnprintf
17 da This is a test.
15 Zeichen zurückkehren würde, fügen Sie den NULL
und Sie erhalten 16
verwandte Themen, die ich gesehen habe, aber befassen sich nicht mit dem Thema:
Mit Antwort des @ Mat (ich bin die Wiederverwendung der va_list
Objekt, was nicht erlaubt ist), das kommt direkt zum ersten verwandten Thread, mit dem ich verlinkt bin. Also habe ich versucht, diesen Code statt:
char *myPrintfInner(const char *message, va_list params)
{
va_list *original = ¶ms;
size_t length = vsnprintf(NULL, 0, message, params);
char *final = (char *) malloc((length + 1) * sizeof(char));
int result = vsnprintf(final, length + 1, message, *original);
printf("vsnprintf result: %d\r\n", result);
printf("%s\r\n", final);
return final;
}
Which, per the C99 spec (Fußnote in Abschnitt 7.15), funktionieren sollte:
Es erlaubt ist, einen Zeiger auf eine va_list zu erstellen und diesen Zeiger zu einem anderen übergeben Funktion, in diesem Fall kann die ursprüngliche Funktion weitere Verwendung der ursprünglichen Liste nach der anderen Funktion zurückgeben.
Aber mein Compiler (gcc 4.4.5 in C99-Modus) gibt mir diesen Fehler in Bezug auf die erste Zeile des myPrintfInner
:
test.c: In function ‘myPrintfInner’:
test.c:8: warning: initialization from incompatible pointer type
und das resultierende binäre erzeugt genau die gleiche Wirkung wie das erste Mal .
Gefunden dies: Is GCC mishandling a pointer to a va_list passed to a function?
Die vorgeschlagene Abhilfe (die nicht zur Arbeit war garantiert, aber in der Praxis hat) ist arg_copy
zu verwenden zuerst:
char *myPrintfInner(const char *message, va_list params)
{
va_list args_copy;
va_copy(args_copy, params);
size_t length = vsnprintf(NULL, 0, message, params);
char *final = (char *) malloc((length + 1) * sizeof(char));
int result = vsnprintf(final, length + 1, message, args_copy);
printf("vsnprintf result: %d\r\n", result);
printf("%s\r\n", final);
return final;
}
Ihre 'myPrintf' -Funktion fehlt eine' return' Anweisung. Ich hätte erwartet, dass dein Compiler dich davor warnen würde. –
bah, humbug! Fehler beim Kopieren und Einfügen –
Ihr neuer Code tut genau das gleiche wie der alte: 'original' zeigt auf' params', also ist das Übergeben von 'original' genau das gleiche wie das Übergeben von' params'. Ihr wirkliches Problem scheint zu sein, dass Sie nicht verstehen, wie 'va_list' funktioniert: Sie sind im Wesentlichen Zeiger auf den Argument-Stack, und der Zeiger wird erhöht, wenn er benutzt wird. Wenn Sie die gleiche 'va_list' zweimal verwenden, erhöhen Sie den Zeiger das zweite Mal nach dem Ende der Argumentliste. –