在Julia中,为什么@printf是一个宏而不是一个函数?

73

在Julia中,打印格式化字符串的语法如下:

@printf("Hello %d\n", 5)

@printf 为什么是宏而不是函数?是因为它可以接受可变数量的参数吗?

2个回答

129

对于普通的Julia函数来说,接受可变数量的参数并不是问题 [1]。 @printf 是一个宏,因此它可以在编译时解析和解释格式字符串,并为该特定格式字符串生成自定义代码。人们可能没有意识到C语言中的printf函数会在每次调用printf时重新解析和重新解释格式字符串。事实上,它能够如此之快,这代表了疯狂指针编程的小奇迹。认真看一下你最近的libc的printf实现,它完全是疯狂的。

朱莉娅使用了不同的方法:@printf是一个宏,它将格式化字符串转换为与该格式规范特定的高效代码。如果你思考一下,printf风格的格式化字符串实际上只是一种表达方式,可以以特定的方式打印固定数量和类型的参数的函数。请注意,我说的是格式化字符串是一个函数,而不是printf本身,后者在概念上是一个函数生成器,将格式转换为格式化程序。这一切之所以被塞进C中的运行时函数,有点不太匹配,因为这是在C中唯一合理的选项。事实上,由于这一点,直到最近,通过向C的printf传递错误的数量或类型的参数很容易犯错。这只有现在更好,因为编译器已经被特别处理,以理解printf格式的语义。
在理论上,Julia的@printf可以比C更快,因为它生成自定义代码,但在实践中,我很难达到C的水平,更不用说超越它了。但我认为这是由于我们I/O系统的当前设计以及我使用它的方式所致,并非固有的限制。不过,I/O部分需要进行全面改进,当这一点发生时,我们可能会利用@printf是宏这一事实,在格式化打印方面击败C。

2
@lucacerone 执行 x = @sprintf "我的幸运数字是 %d" 42 - Adobe
3
为每个printf调用生成自定义代码很可能会导致大量的代码膨胀。 - vitaut
14
@StefanKarpinski 在这里提供了有趣的更新。 (链接:https://github.com/JuliaLang/julia/pull/11941#issuecomment-129966921) - Jim Garrison
3
这种方法的一个缺点似乎是格式化字符串不能包含变量。请参见http://julia-programming-language.2336112.n4.nabble.com/string-BigFloat-disable-scientific-notation-td21455.html。 - user44400
2
不能将变量用作格式字符串不仅是一个缺点,而且是一个重要的限制。如果字符串是静态的,编译器应该进行静态优化,并在运行时解析printf函数。否则,使用变量格式是一个相当常见的用例。 - theferrit32
显示剩余2条评论

7

这是为了提高性能。 printf 宏接受一个常量格式字符串(例如:"Hello %d\n")并为该字符串生成优化代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接