Во время интервью я просил (среди прочего) осуществлять следующие функции:Что касается vsnprintf (интервью)
int StrPrintF(char **psz, const char *szFmt, ...);
, похожий на sprintf
, за исключением того, вместо уже выделенной памяти функция должна выделить его сама , и вернуться в переменную *psz
. Более того, *psz
может указывать на уже выделенную строку (в куче), которая потенциально может использоваться во время форматирования. Естественно, эта строка должна быть бесплатной с помощью соответствующих средств.
Возвращаемое значение должно быть длиной только что созданной строки или отрицательной по ошибке.
Это моя реализация:
int StrPrintF(char **psz, const char *szFmt, ...)
{
va_list args;
int nLen;
va_start(args, szFmt);
if ((nLen = vsnprintf(NULL, 0, szFmt, args)) >= 0)
{
char *szRes = (char*) malloc(nLen + 1);
if (szRes)
if (vsnprintf(szRes, nLen + 1, szFmt, args) == nLen)
{
free(*psz);
*psz = szRes;
}
else
{
free(szRes);
nLen = -1;
}
else
nLen = -1;
}
va_end(args);
return nLen;
}
вопрос автор утверждает, что есть ошибка в этой реализации. Не только стандартное нарушение, которое может терпеть неудачу в конкретных эзотерических системах, но это «настоящая» ошибка, которая случайно может потерпеть неудачу в большинстве систем.
Это также не относится к использованию int
вместо подходящего для памяти типа, такого как size_t
или ptrdiff_t
. Скажем, строки имеют «разумный» размер.
Я действительно не знаю, что может быть ошибкой. Вся арифметика указателя в порядке ИМХО. Я даже не предполагаю, что два последовательных вызова vsnprintf
дают тот же результат. Все материалы с вариационной обработкой также правильны ИМХО. va_copy
не требуется (это ответственность вызывающего абонента, который использует va_list
). Также на x86 va_copy
и va_end
бессмысленны.
Буду признателен, если кто-то может обнаружить (потенциальную) ошибку.
EDIT:
После проверки ответов и комментариев - я хотел бы добавить некоторые примечания:
- Естественно я построил и запустить код с различными входами, включая стадию -by-step в отладчике, наблюдая за состоянием переменных. Я никогда не прошу помощи, не пробовав себя в первую очередь. Я не видел никаких проблем, не повреждал кучу/кучу и т. Д. Также я запустил его в сборке отладки, с включенной отладочной кучей (которая непереносима для кучи коррупции).
- Я предполагаю, что функция вызывается с действительными параметрами, т.е.
psz
является допустимым указателем (не путать с*psz
),szFmt
является действительным спецификатором формата, и все VARIADIC параметров оцениваются и соответствуют строке формата. - Вызов
free
с указателемNULL
в порядке в соответствии со стандартом. - Вызов
vsnprintf
в порядке сNULL
Указатель и размер = 0. Он должен вернуть результирующую длину строки. MS-версия, хотя и не полностью стандартная, делает то же самое в этом конкретном случае. vsnprintf
не будет превышать указанный размер буфера, включая 0-терминатор. Значит - он не всегда его размещает.- Пожалуйста, отложите стиль кодирования в сторону (если вам это не нравится - отлично со мной).
Вы пробовали компилировать и запускать некоторый тестовый код на вашем компьютере? –
Проблема с 'snprintf()', но я не уверен, что она применяется к 'vsnprintf()' ... –
Я считаю, что документы для 'vsnprintf' указывают, что вывод * всегда * с нулевым завершением , поэтому ваш вызов 'vsnprintf (NULL, ...)' может вызвать ошибку seg. –