2010-05-10 40 views
2

带有printf格式字符串的各种函数在遇到%c格式时的行为如何,给定值为\0/NULL? 他们应该如何表现?它安全吗?它被定义了吗?它是编译器特定的吗?printf(“...%c ...”,' 0')和家人 - 会发生什么?

例如sprintf() - 它会裁剪NULL的结果字符串吗?它会返回多长?

printf()输出整个格式字符串还是刚达到新的NULL?

va_args + vsprintf/vprintf受到某种程度的影响吗?如果是这样,怎么样?

我是否会冒内存泄漏或其他问题?在std :: string.c_str()中的一个点上拍这个NULL?

什么是避免这种警告(净化输入?)

+2

宏NULL和字符'\ 0'不是一回事。后者通常用ASCII助记符NUL表示,但与NULL不同。 – Clifford 2010-05-10 19:04:25

+0

@Clifford:系统,NULL不是零存在过去,但现在,除非你编程一些长期过时的大铁恐龙,否则你不会遇到这个警告。 – 2014-09-24 12:43:10

+0

我想你会错过我的观点 - 'NULL'是一个表示空*指针*的宏,而'\ 0'是一个字符常量(在C中是'int'类型,在C++中是'char')。此外,无论空指针的实际机器相关位模式如何,C++ *都可以保证*零可以隐式转换为这样的指针。我的观点是,在这种情况下,你可以引用nul,null-character,NUL或'\ 0',但不应该使用宏NULL来表示这样的字符。将这个单词放在'code mark-up'中可能意味着NULL宏。 – Clifford 2014-09-24 16:46:09

回答

3

输出NUL时会发生什么取决于输出设备。

这是一个非打印字符,即isprint('\0') == 0;所以当输出到显示设备时,它没有明显的影响。但是,如果重定向到文件(或者调用fprintf()),它会在文件中插入一个NUL(零字节)。这个意思取决于文件的使用方式。

当输出到一个C字符串时,它将被标准字符串处理函数解释为一个字符串终止符,尽管任何其他后续格式说明符仍然会导致数据在NUL之后被放置在缓冲区中,标准字符串处理函数。如果最终数组不被解释为C字符串,这可能仍然有用。

我是否会冒内存泄漏或其他问题?在std :: string.c_str()中的一个点上拍这个NULL?

这是完全不清楚你的意思是什么,但如果你使用的是由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',,'\n','\r')。

请注意,您也可以考虑isprint()而非isgraph(c) || isspace(c),但不包括'\t''\f',,'\n''\r'

8

的任何功能,需要一个标准的C柱会停在第一个空,不管它如何到达那里的最佳途径。

当您以格式使用%c并将字符值使用0时,它会在输出中插入一个空值。 printf将输出null作为输出的一部分。 sprintf也会将null插入到结果字符串中,但当您将输出传递给另一个函数时,该字符串将显示在该点结束。

std :: string会在其内容的任何地方愉快地包含null,但是当你用c_str方法将它传递给一个函数时,请参阅上面的答案。

+0

尽管这被标记为由我编辑,但实际上我只是在意外编辑它而不是我自己的条目后将其还原为原始。抱歉。 (我因为自己的无能而获得“清理”徽章!?) – Clifford 2010-05-10 19:41:59

3

printf()sprintf()将继续过去插入%c一个'\0'角色,因为它们的输出被定义格式字符串内容的术语,而%c不表示格式字符串的结尾。

这包括他们的计数;因此:

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

必须始终返回3(尽管strlen(x)之后将返回1)。