У меня есть код, который преобразует переменные параметры в va_list
, а затем передает список в функцию, которая затем вызывает vsnprintf
. Это прекрасно работает в Windows и OS X, но в Linux это приводит к странным результатам.
В следующем примере кода:
#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;
}
Выход второго vsnprintf
вызова равен 17, а результат strcmp
равен 31; но я не понимаю, почему vsnprintf
вернул бы 17, поскольку This is a test.
- 15 символов, добавьте NULL
, и вы получите 16.
Связанные темы, которые я видел, но не затрагиваю тему:
С ответом @ Mat (я повторно использую объект va_list
, который не разрешен), это прямо касается первой связанной нити, с которой я связался. Поэтому я попытался использовать этот код:
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;
}
Что, согласно спецификации C99 (сноска в Разделе 7.15), должно работать:
Разрешено создавать указатель на va_list и передавать этот указатель
другой функции, в этом случае оригинальная функция может сделать
дальнейшее использование исходного списка после возврата другой функции.
Но мой компилятор (gcc 4.4.5 в режиме C99) выдает мне эту ошибку относительно первой строки myPrintfInner
:
test.c: In function ‘myPrintfInner’:
test.c:8: warning: initialization from incompatible pointer type
И полученный двоичный файл производит тот же эффект, что и в первый раз.
Нашел это: Неправильно ли обрабатывает GCC указатель на va_list, переданный в функцию?
Предлагаемый обходной путь (который не гарантированно сработал, но работал на практике) - сначала использовать arg_copy
:
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;
}