printf ("...% c ...", '\ 0') и family - что будет? - PullRequest
2 голосов
/ 10 мая 2010

Как будут вести себя различные функции, принимающие строку формата printf, при обнаружении в формате %c заданного значения \0 / NULL? Как они должны себя вести? Это безопасно? Это определено? Это зависит от компилятора?

например. sprintf() - будет ли обрезать строку результата в NULL? Какую длину он вернет?

Будет ли printf() выводить всю строку формата или только до нового значения NULL?

Будет ли как-то затронуто va_args + vsprintf / vprintf? Если да, то как?

Есть ли риск утечки памяти или других проблем, если я, например, снимать этот NULL в точке в std :: string.c_str ()?

Каковы наилучшие способы избежать этого предостережения (дезинфицировать вход?)

Ответы [ 3 ]

8 голосов
/ 10 мая 2010

Любая функция, которая принимает стандартную строку C, остановится на первом нуле, независимо от того, как она туда попала.

Когда вы используете% c в формате и используете 0 для символьного значения, он вставит нуль в вывод. printf будет выводить ноль как часть вывода. sprintf также вставит значение NULL в строку результата, но строка будет заканчиваться в тот момент, когда вы передадите вывод другой функции.

std :: string с радостью будет содержать ноль в любом месте своего содержимого, но когда вы возьмете метод c_str, чтобы передать его функции, смотрите ответ выше.

3 голосов
/ 11 мая 2010

printf() и sprintf() будут продолжаться после символа '\0', вставленного с %c, поскольку их вывод определяется в терминах содержимого строки формата, а %c не обозначает конец строка формата.

Это включает их количество; таким образом:

sprintf(x, "A%cB", '\0')

всегда должен возвращать 3 (хотя strlen(x) впоследствии возвращает 1).

3 голосов
/ 10 мая 2010

Что происходит, когда вы выводите NUL, зависит от устройства вывода.

Это непечатный символ, т.е. isprint('\0') == 0; поэтому при выводе на устройство отображения оно не оказывает видимого влияния. Однако, если он перенаправлен в файл (или при вызове fprintf()), он вставит в файл NUL (нулевой байт); значение этого будет зависеть от того, как файл используется.

При выводе в строку C она будет интерпретироваться как терминатор строки стандартными функциями обработки строк, хотя любые другие последующие спецификаторы формата будут по-прежнему приводить к тому, что данные будут помещены в буфер после NUL, который будет невидим для стандарта функции обработки строк. Это все еще может быть полезно, если в конечном итоге массив не должен интерпретироваться как строка C.

Есть ли риск утечки памяти или других проблем, если я, например, снимать этот NULL в точке в std :: string.c_str ()?

Совершенно неясно, что вы подразумеваете под этим, но если вы предлагаете использовать указатель, возвращаемый std::string.c_str() в качестве буфера для sprintf(); нет! c_str() возвращает const char*, изменение строки через такой указатель не определено. Это, однако, другая проблема, не связанная со вставкой NUL в строку.

Каковы наилучшие способы избежать этого предостережения (дезинфицировать вход?)

Я изо всех сил пытаюсь придумать обстоятельства, при которых вы могли бы «случайно» написать такой код, так зачем вам остерегаться его !? Вы имеете в виду конкретное обстоятельство? Даже если я нахожу это неправдоподобным и, вероятно, ненужным, в чём тут сложность:

if( c != 0 )
{
    printf( "%c", c ) ;
}

или, возможно, более полезный (так как в выводе есть другие символы, которых вы можете избежать)

if( isgraph(c) || isspace(c) )
{
    printf( "%c", c ) ;
}

, который будет выводить только видимые символы и пробелы (пробел, '\t', '\f', '\v', '\n', '\r').

Обратите внимание, что вы также можете рассмотреть isprint(), а не isgraph(c) || isspace(c), но это исключает '\t', '\f', '\v', '\n' и '\r'

...