Unix для Windows: альтернатива vsnprintf для определения длины? - PullRequest
11 голосов
/ 13 декабря 2011

В настоящее время я конвертирую код одной из наших библиотек Linux в Windows DLL.

В этой библиотеке у меня есть функция, которая принимает последние параметры в printf-way (строка формата, затем многоточие). В этой функции я использую vsnprintf для форматирования предоставленных аргументов. Так как я хочу знать, могу ли я втиснуть последнюю строку в небольшой буфер или мне нужно было бы выделить Память для этого, я заинтересован в определении "будущей длины" отформатированной строки.

Для этого я в настоящее время использую vsnprintf, как это (очевидно, составленный пример кода):

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

void foo(const char* fmt, ...)
{
   int len = 0;
   va_list ap;

   va_start(ap, fmt);
   len = vsnprintf(0, 0, fmt, ap);
   printf("len = %d\n", len);
   va_end(ap);
}

int main(void)
{
   foo("12345%s", "67890");
   exit(0);
}

На это использование распространяется Открытая группа базовых спецификаций, выпуск 6 :

vsnprintf (char * restrict s, size_t n, const char * restrict format, va_list ap)

Функции [...] vsnprintf () [...] должны быть эквивалентны функции [...] snprintf ().

snprintf (char * restrict s, size_t n, const char * restrict format, ...)

Если при вызове snprintf () значение n равно нулю, ничего не должно быть записано, должно быть возвращено количество байтов, которое было бы записано, если бы n было достаточно большим, исключая завершающий ноль, и s может быть нулевым указателем.

Проблема возникла, когда я компилировал этот код в системе Windows (Visual Studio 2010) с параметром / analysis. Компилятор / анализатор дал мне следующее:

test.c (11): предупреждение C6309: Аргумент '1' равен нулю: это не соответствует спецификации функции 'vsnprintf'

test.c (11): предупреждение C6387: «аргумент 1» может быть «0»: это не соответствует спецификации для функции «vsnprintf»: строки: 7, 8, 10, 11

Быстрый просмотр записи MSDN для vsnprintf дал мне следующее:

Если буфер или формат равен NULL , или если число меньше или равно нулю, эти функции вызывают недопустимый обработчик параметров, как описано в Проверка параметров. Если выполнение может продолжаться, эти функции возвращают -1.

Любопытно, что приведенный выше пример, тем не менее, работает на Windows "как положено" (то есть возвращает количество подсчитанных символов).

Но так как я не хочу, чтобы это зависело от чего-то неопределенного, я хотел бы знать, есть ли лучший, официальный способ достижения того же самого, без надежды, что это не сломается в каком-то будущем выпуске.

Спасибо за ваше время!

Ответы [ 2 ]

10 голосов
/ 13 декабря 2011

Ответ, предоставленный в комментариях Hans Passant :

Документированный _vscprintf предоставляет эту функциональность в Windows, поэтому полагаться на "неопределенное поведение" не нужно.

3 голосов
/ 13 декабря 2011

Взять этот пример со страницы руководства snprintf :

Вот как выделить буфер для размещения вашей строки.

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

char *
make_message(const char *fmt, ...)
{
    int n;
    int size = 100;     /* Guess we need no more than 100 bytes. */
    char *p, *np;
    va_list ap;

   if ((p = malloc(size)) == NULL)
        return NULL;

   while (1) {

       /* Try to print in the allocated space. */

       va_start(ap, fmt);
        n = vsnprintf(p, size, fmt, ap);
        va_end(ap);

       /* If that worked, return the string. */

       if (n > -1 && n < size)
            return p;

       /* Else try again with more space. */

       if (n > -1)    /* glibc 2.1 */
            size = n+1; /* precisely what is needed */
        else           /* glibc 2.0 */
            size *= 2;  /* twice the old size */

       if ((np = realloc (p, size)) == NULL) {
            free(p);
            return NULL;
        } else {
            p = np;
        }
    }
}
...