该 printf 功能 的 将 强> 写给 stdout 。它不符合优化 /dev/null 。 因此,您将有解析格式字符串和评估任何必要参数的开销,并且您将至少有一个系统调用,并且您将缓冲区复制到内核地址空间(与系统调用的成本相比,这是可忽略的) 。
printf
stdout
/dev/null
这个答案基于POSIX的具体文档。
的 系统接口 强> dprintf,fprintf,printf,snprintf,sprintf - 打印格式化输出 fprintf()函数应将输出放在命名输出流上。 printf()函数应将输出放在标准输出流stdout上。 sprintf()函数应将输出后跟空字节'\ 0'放在从* s开始的连续字节中;用户有责任确保有足够的空间。 的 基础定义 强> 应 对于符合POSIX.1-2017的实现,描述了必需的功能或行为。应用程序可以依赖于特征或行为的存在。
的 系统接口 强> dprintf,fprintf,printf,snprintf,sprintf - 打印格式化输出
fprintf()函数应将输出放在命名输出流上。 printf()函数应将输出放在标准输出流stdout上。 sprintf()函数应将输出后跟空字节'\ 0'放在从* s开始的连续字节中;用户有责任确保有足够的空间。
的 基础定义 强> 应 对于符合POSIX.1-2017的实现,描述了必需的功能或行为。应用程序可以依赖于特征或行为的存在。
一般而言,如果实现不影响程序的可观察(功能)输出,则允许执行此类优化。如果是 printf() ,这意味着如果程序不使用返回值,如果没有 %n 转换,然后执行将被允许什么都不做。
printf()
%n
在实践中,我不知道Linux上当前(2019年初)执行这样的优化的任何实现 - 我熟悉的编译器和库将格式化输出并将结果写入空设备,依赖于内核'忽略它。
如果你真的需要在不使用输出时节省格式化成本,你可能想要编写自己的转发功能 - 你会希望它返回 void ,你应该检查格式字符串 %n 。 (你可以用 snprintf 用一个 NULL 和 0 缓冲,如果你需要这些副作用,但节省不太可能回报投入的努力)。
void
snprintf
NULL
0
差不多。
当您将程序的stdout重定向到 /dev/null ,任何电话 printf(3) 仍将评估所有参数,字符串格式化过程仍将在调用之前进行 write(2) ,将完整格式化的字符串写入进程的标准输出。在内核级别,数据不会写入磁盘,而是由与特殊设备关联的处理程序丢弃 /dev/null 。
printf(3)
write(2)
因此,在最好的情况下,您不会绕过或逃避评估参数并将其传递给它们的开销 printf ,后面的字符串格式化作业 printf ,至少有一个系统调用实际写入数据,只需将stdout重定向到 /dev/null 。嗯,这是Linux的真正区别。实现只返回您想要写入的字节数(由您调用的第3个参数指定) write(2) 并忽略其他一切(见 这个答案 )。根据您正在编写的数据量以及目标设备(磁盘或终端)的速度,性能差异可能会有很大差异。在嵌入式系统上,一般来说,通过重定向来切断磁盘写入 /dev/null 可以为一些非常重要的书面数据节省相当多的系统资源。
虽然理论上该程序可以检测到 /dev/null 并且在他们遵守的标准(ISO C和POSIX)的限制内执行一些优化,基于对常见实现的一般理解,他们实际上没有(即我不知道任何Unix或Linux系统这样做)。
POSIX标准要求写入标准输出以进行任何调用 printf(3) ,所以它不符合标准 - 禁止调用 write(2) 取决于相关的文件描述符。有关POSIX要求的更多详细信息,请阅读 达蒙的回答 。哦,快速说明:所有Linux发行版都符合POSIX标准,尽管不是 认证 是这样的。
请注意,如果您更换 printf 例如,完全可能会出现一些副作用 printf("%d%n", a++, &b) 。如果你真的需要根据程序执行环境来抑制输出,可以考虑设置一个全局标志并包装printf以在打印之前检查标志它不会使程序速度降低到性能损失的程度是可见的,因为单个条件检查是 许多 比打电话快 printf 并执行所有字符串格式化。
printf("%d%n", a++, &b)
使用printf()源作为指导来编写自己的包装printf(),如果设置了noprint标志,则立即返回。这样做的缺点是,实际打印时会因为必须解析格式字符串两次而消耗更多资源。但是在不打印时它使用的资源可以忽略不计。不能简单地替换printf(),因为printf()中的底层调用可以使用较新版本的stdio库进行更改。
void printf2(const char * formatstring,...);