Перекрывающаяся память с помощью sprintf (snprintf) - PullRequest
0 голосов
/ 27 октября 2018

Редактировать: Как насчет того, если бы у нас было

char value_arr[8];    
// value_arr is set to some value
snprintf(value_arr, 8, "%d", *value_arr);

это поведение определено?


Скажем по какой-то неуклюжей причине, что у меня

char value_arr[8];
// value_arr is set to some value
int* value_i = reinterpret_cast<int*>(value_arr);

snprintf(value_arr, 8, "%d", *value_i); // the behaviour in question

Есть ли гарантия, что, например, если *value_i = 7, то value_arr примет значение "7".Это поведение определено?Таким образом, value_i сначала разыменовывается, затем передается по значению, а затем форматируется, а затем сохраняется в массиве.

Обычно можно ожидать, что значение *value_i не изменится, но сохранит строку вvalue_arr нарушает это.

Кажется, он работает, как и ожидалось, когда я тестирую его, но я не могу найти окончательного ответа в документации.Сигнатура функции имеет ..., что, насколько мне известно, имеет отношение к va_list, но, боюсь, я не очень разбираюсь в работе функций с переменными числами.

int sprintf (char* str, const char* format, ... );

Ответы [ 3 ]

0 голосов
/ 27 октября 2018

Это неопределенное поведение;Вы используете указатель типа int*, чтобы указать на объект типа char[8] с другими / менее строгими требованиями к выравниванию по сравнению с int*.Разыменование этого указателя приводит к UB.

0 голосов
/ 27 октября 2018

Следующее можно найти на https://en.cppreference.com/w/cpp/io/c/fprintf:

Если вызов sprintf или snprintf вызывает копирование между перекрывающимися объектами, поведение не определено.

Я бы истолковал ваш пример, чтобы он попал в этот случай, и в соответствии с этой страницей он будет классифицирован как Неопределенное поведение.

Редактировать: некоторые подробности на https://linux.die.net/man/3/snprintf:

Некоторые программы неосторожно полагаются на код, такой как следующий

sprintf (buf, "% s, дополнительный текст", buf);

для добавления текста в буфер. Однако в стандартах прямо указано, что результаты не определены, если исходные и конечные буферы перекрываются при вызове sprintf (), snprintf (), vsprintf () и vsnprintf (). В зависимости от используемой версии gcc (1) и используемых опций компилятора вызовы, подобные приведенным выше, не будут давать ожидаемых результатов.

0 голосов
/ 27 октября 2018

Для исходного кода вычисление выражения *value_i вызывает неопределенное поведение, нарушая правило строгого алиасинга.Не разрешается использовать псевдоним массива символов как int.

. Для отредактированного кода snprintf(value_arr, 8, "%d", *value_arr); это нормально и отформатирует код символа первого символа в массиве.Оценка аргументов функции выполняется до входа в функцию.(C ++ 17 intro.execution / 11)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...