printf("... %c ...",'\0') 和家人 - 会发生啥?

Posted

技术标签:

【中文标题】printf("... %c ...",\'\\0\') 和家人 - 会发生啥?【英文标题】:printf("... %c ...",'\0') and family - what will happen?printf("... %c ...",'\0') 和家人 - 会发生什么? 【发布时间】:2010-05-10 15:48:39 【问题描述】:

在遇到%c 格式给定值\0/NULL 时,采用 printf 格式字符串的各种函数将如何表现? 他们应该如何表现?安全吗?定义了吗?它是特定于编译器的吗?

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

printf() 会输出整个格式字符串还是只输出新的 NULL?

va_args + vsprintf/vprintf 会受到某种影响吗?如果有,怎么做?

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

避免这种警告的最佳方法是什么(清理输入?)

【问题讨论】:

宏 NULL 和字符 '\0' 不是一回事。后者通常用 ASCII 助记符 NUL 表示,但这也与 NULL 不同。 @Clifford:过去存在 NULL 不为零的系统,但现在除非你正在编写一些早已过时的大型铁恐龙,否则你没有遇到这个警告的风险。跨度> 我想你没抓住我的意思 - NULL 是一个代表空 指针 的宏,而 \0 是一个字符常量(在 C 和char 在 C++ 中)。此外,不管空指针的实际机器相关位模式如何,C++ 保证零可以隐式转换为这样的指针。我的观点是,在这种情况下,您可以引用 nul、空字符、NUL 或 \0,但不应使用宏 NULL 来表示这样的字符。将单词放在code mark-up 中可能意味着NULL 宏。 【参考方案1】:

任何采用标准 C 字符串的函数都会在第一个 null 处停止,无论它是如何到达那里的。

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

一个 std::string 很乐意在其内容中的任何位置包含一个 null,但是当您使用 c_str 方法将其传递给函数时,请参阅上面的答案。

【讨论】:

尽管这被标记为由我编辑,但实际上我只是在不小心编辑它而不是我自己的条目之后将其恢复为原始状态。对不起。 (而且我因为自己的无能而获得了“清理”徽章!?)【参考方案2】:

输出 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''\v''\n''\r')。

请注意,您可能还会考虑isprint() 而不是isgraph(c) || isspace(c),但不包括'\t''\f''\v''\n''\r'

【讨论】:

【参考方案3】:

printf()sprintf() 将继续经过插入 %c'\0' 字符,因为它们的输出是根据格式字符串的内容定义的,而 %c 不表示结尾格式化字符串。

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

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

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

【讨论】:

以上是关于printf("... %c ...",'\0') 和家人 - 会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章

几道C笔试题

有以下程序: main( ) int a[10]=1,2,3,4,5,6,7,8,9,10,*p=&a[3],*q=p-2; printf("%d\n",*p+*q);

求大神,关于c语言删除函数

几道C笔试题

C语言 条件语句

c语言结构体调用