На что указывает arg в va_start?
Вот код. Комментарием пометил место, где возникает вопрос. Данный printf() выводит размер в 9 байт. Я не очень понимаю, как это работает.
char* add_to_string(const char *format, char *dest, ...)
{
va_list arg;
int user_str_size = sizeof(*dest) * strlen(dest);
va_start(arg, dest);
int new_size = vsnprintf(NULL, 0, format, arg);
printf("Size %d\n", new_size); // не понимаю вывод в этом месте!
va_end(arg);
dest = (char *)realloc(dest, sizeof(char) * new_size + 1);
va_start(arg, dest);
vsnprintf(dest + strlen(dest), new_size - user_str_size + 1, format, arg);
va_end(arg);
return dest;
}
char *r = strdup("Aa ");
r = add_to_string("%s %s %s", r, "Bb", "Cc");
Вывод моей программы: Size 9 Aa Bb Cc
Получается, что arg указывает на dest, а не на элементы после него, так? Вот пример из интернета.
void PrintFError ( const char * format, ... )
{
char buffer[256];
va_list args;
va_start (args, format);
vsnprintf (buffer,256,format, args);
perror (buffer);
va_end (args);
}
int main ()
{
FILE * pFile;
char szFileName[]="myfile.txt";
pFile = fopen (szFileName,"r");
if (pFile == NULL)
PrintFError ("Error opening '%s'",szFileName);
else
{
// file successfully open
fclose (pFile);
}
return 0;
}
Вывод их программы: Error opening file 'myfile.txt': No such file or directory
Так вот у меня вопрос, на что указывает arg после va_start? Почему мой vsprintf возвращает 9, а не 6. Почему в программе из интернета их format не подставляется в строку результата. Если бы их vsprintf работал бы так же, то они бы получили в результате строку "Error opening 'Error opening '%s''", потому что args указывает на формат. Проще говоря, я не понимаю, почему строка 'Aа ' в принципе учитывается в первом вызове vsprintf и первый вызов возращает мне 9,а не 6
Ответы (1 шт):
arg в va_start(arg, dest); указывает на аргумент, следующий в списке вызова непосредственно за dest.
У меня (Linux, 64-bit) поведение вашей программы (из-за ошибки -- лишний %s в формате %s %s %s) не воспроизводится.
Предполагаю, что это связано с тем, что у вас 32-бит ОС, параметры передаются через стек и в вашем случае лишний аргумент (который вы не передаете в vsnprintf()) адресует "удачно расположеный" мусор в памяти.
Насколько я понял задумку
(добавить к строке, передаваемой во втором аргументе, содержимое строк из 3-го и 4-го аргументов)
правильный вариант функции должен быть вот таким:
char* add_to_string(const char *format, char *dest, ...)
{
va_list arg;
int user_str_size = strlen(dest);
va_start(arg, dest);
int new_size = vsnprintf(NULL, 0, format, arg);
printf("Size %d\n", new_size); // не понимаю вывод в этом месте!
va_end(arg);
dest = (char *)realloc(dest, user_str_size + new_size + 1);
va_start(arg, dest);
vsnprintf(dest + user_str_size, user_str_size + new_size, format, arg);
va_end(arg);
return dest;
}
Естественно, при вызове строка формата должна содержать 2 %s
char *r = strdup("Aa ");
r = add_to_string("%s %s", r, "Bb", "Cc");
printf("r = <%s>\n", r);