Я просто интересно, если это выражение является безопасным:printf: Это безопасно?
int main (void)
{
char my_tab[256];
memset(my_tab,0x61,sizeof(my_tab));
printf("Is it safe ? : %.256s",my_tab); /* is it safe ? */
}
Я просто интересно, если это выражение является безопасным:printf: Это безопасно?
int main (void)
{
char my_tab[256];
memset(my_tab,0x61,sizeof(my_tab));
printf("Is it safe ? : %.256s",my_tab); /* is it safe ? */
}
Да, вы не напечатаете 256 символов, и больше ничего.
От C11-Standard 7.21.6. р4:
Необязательное точность, что дает минимальное количество цифр появляются на D, I, о, и, преобразование х, и X, количество цифр появляться после десятичной точки для конверсий a, A, e, E, f и F , максимальное количество значащих цифр для конверсий g и G , или максимальное количество байтов, которое должно быть записано для преобразований s . Точность принимает вид периода (.), Который следует за либо звездочкой * (описанной ниже), либо необязательным десятичным числом ; если указан только период, точность принимается как ноль. Если точность отображается с любым другим спецификатором преобразования, поведение не определено.
7.21.6.1. P8:
s: Если ни один модификатор л Длина не присутствует, аргумент должен быть указателем на начальный элемент массива символьного типа. Символами из массива являются , записанные до (но не включая) завершающий нулевой символ. Если указана точность , пишется не более чем много байтов. Если точность не указана или больше размера массива, массив должен содержать нулевой символ.
Я не совсем уверен. Предположим, что реализация выполняет 'strlen()', чтобы узнать, как долго строка? Так что это должно быть безопасно, но может и не быть. – JeremyP
@JeremyP Если моя реализация делает это, тогда я хочу вернуть свои деньги! – ams
@JeremyP: Вопрос о 'printf()' ing not 'strlen()' ing, не так ли? – alk
Да, это должно быть безопасным. Реализации, которые пытаются получить доступ к символу за концом буфера, считаются недействительными.
псевдокод для обработки %.Ns
, где N
представляет собой число, должно выглядеть следующим образом:
size_t count = 0;
size_t N = ...;
char *ptr = <next-arg>;
while (count < N && *ptr != '\0') {
putchar(*ptr++);
count++;
}
Обратите внимание, что приведенный выше код никогда не будет ссылаться на характер мимо N
.
Можно представить реализацию, которая инвертирует условие цикла while
, которое будет обращаться к байту за концом буфера. Однако такая реализация будет недействительной, поскольку в соответствии со стандартом для реализации требуется закончить нулевой ограничитель, только если размер не указан или он больше числа пройденных символов:
[7.19.6.1.8] Если точность не указана или больше размера массива, массив должен содержать нулевой символ.
Существует хорошее стандартное имя для «' output_to_buffer': 'putchar'. :-) –
@R .. Спасибо! Думаю, я тоже должен заменить свой '
Это безопасно.
С Е (3) - страница Linux руководство http://man7.org/linux/man-pages/man3/printf.3.html:
s If no l modifier is present: The const char * argument is expected to be a pointer to an array of character type (pointer to a string). Characters from the array are written up to (but not including) a terminating null byte ('\0'); if a precision is specified, no more than the number specified are written. If a precision is given, no null byte need be present; if the precision is not specified, or is greater than the size of the array, the array must contain a terminating null byte.
Функция vsnprintf в /lib/vsprintf.c вызова strnlen (s, spec.precision) для получения отформатированной буквы:
/**
* strnlen - Find the length of a length-limited string
* @s: The string to be sized
* @count: The maximum number of bytes to search
*/
size_t strnlen(const char *s, size_t count)
{
const char *sc;
for (sc = s; count-- && *sc != '\0'; ++sc)
/* nothing */;
return sc - s;
}
Доступны только действительные байты символов.
static noinline_for_stack
char *string(char *buf, char *end, const char *s, struct printf_spec spec)
{
int len, i;
if ((unsigned long)s < PAGE_SIZE)
s = "(null)";
len = strnlen(s, spec.precision);
if (!(spec.flags & LEFT)) {
while (len < spec.field_width--) {
if (buf < end)
*buf = ' ';
++buf;
}
}
for (i = 0; i < len; ++i) {
if (buf < end)
*buf = *s;
++buf; ++s;
}
while (len < spec.field_width--) {
if (buf < end)
*buf = ' ';
++buf;
}
return buf;
}
Тот факт, что конкретная реализация 'printf',' 'vsnprintf' или' strnlen' не задыхается от аргумента, который не указывает на нуль -терминированная строка имеет значение только для этой конкретной реализации. Важным моментом является то, что стандарт C требует его безопасности. Особая реализация 'strlen' может быть хорошо выполнена с учетом аргумента нулевого указателя, но' strlen (NULL) 'все еще имеет неопределенное поведение. –
Если '0x61' соответствует«безопасной»характер (я предлагаю использовать' 'a'' вместо этого), это безопасно - не каждый компьютер там использует ASCII :) – pmg
Вы правы, я использовал 0x61 только для того, чтобы получить что-то отличное от «\ 0» – Joze
Чтобы быть в безопасности, вам нужно «#include» и '#include ' –
pmg