printf( %c ,'\0') и семья - что произойдет?

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

например sprintf() - обрежет ли результирующая строка значение NULL? Какой длины он вернется?

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

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

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

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


person SF.    schedule 10.05.2010    source источник
comment
Макрос NULL и символ '\0' не одно и то же. Последнее часто обозначается мнемоникой ASCII NUL, но это тоже не то же самое, что NULL.   -  person Clifford    schedule 10.05.2010
comment
@Clifford: Системы, в которых NULL не был равен нулю, существовали в прошлом, но в настоящее время, если вы не программируете каких-то давно устаревших больших железных динозавров, вы не рискуете столкнуться с этим предостережением.   -  person SF.    schedule 24.09.2014
comment
Я думаю, вы упустили мою мысль: NULL — это макрос, представляющий нулевой указатель, а \0 — символьная константа (типа int в C и char в C++). Более того, независимо от фактического машинно-зависимого битового шаблона нулевого указателя, C++ гарантирует, что ноль может быть неявно преобразован в такой указатель. Я хотел сказать, что в этом контексте вы можете ссылаться на nul, нулевой символ, NUL или \0, но не должны использовать макрос NULL для представления такого символа. Размещение слова в code mark-up может подразумевать макрос NULL.   -  person Clifford    schedule 24.09.2014


Ответы (3)


Что происходит, когда вы выводите 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'.

person Clifford    schedule 10.05.2010

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

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

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

person Mark Ransom    schedule 10.05.2010
comment
Несмотря на то, что это было помечено как отредактированное мной, на самом деле я просто вернул его к оригиналу после того, как случайно отредактировал его вместо своей собственной записи. Извиняюсь. (и я получаю значок очистки за собственную некомпетентность!?) - person Clifford; 10.05.2010

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

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

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

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

person caf    schedule 11.05.2010