在 Julia 中,为啥 @printf 是宏而不是函数?

Posted

技术标签:

【中文标题】在 Julia 中,为啥 @printf 是宏而不是函数?【英文标题】:In Julia, why is @printf a macro instead of a function?在 Julia 中,为什么 @printf 是宏而不是函数? 【发布时间】:2013-11-15 23:24:21 【问题描述】:

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

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

为什么@printf 是宏而不是函数?是否可以接受不同数量的参数?

【问题讨论】:

【参考方案1】:

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

Julia 使用不同的方法:@printf 是一个宏,可将格式字符串转换为特定于该格式规范的高效代码。如果您考虑一下,printf 样式的格式字符串实际上只是一种表达函数的方式,该函数采用固定数量和类型的参数并以特定方式打印它们。请注意,我说 format string 是一个函数,而不是 printf 本身,它在概念上是一个函数生成器,将格式转换为格式化程序。这一切都被塞进了 C 中的运行时函数,这有点不匹配,因为这是 C 中唯一合理的选择。事实上,正因为如此,直到最近,你还是很容易自爆通过将错误数量或类型的参数传递给 C 的 printf 在脚上。这只是现在更好,因为编译器已经被特殊情况下理解 printf 格式的语义。

理论上,Julia 的@printf 可以比 C 更快,因为它会生成自定义代码,但实际上,我很难匹配 C,更不用说击败它了。但我认为这是由于我们 I/O 系统的当前设计以及我如何使用它,而不是固有的限制。不过,I/O 的内容应该进行大修,当这种情况发生时,我们实际上可以利用 @printf 是一个宏这一事实在格式化打印方面击败 C。

【讨论】:

@lucacerone do x = @sprintf "My lucky number is %d" 42. 为每个 printf 调用生成自定义代码可能会导致大量代码膨胀。 来自@StefanKarpinski here的有趣更新 看来这种方法的一个缺点是格式字符串不能包含变量。见julia-programming-language.2336112.n4.nabble.com/… 不能将变量用作格式字符串这一事实不仅是一个缺点,而且是一个重大限制。如果字符串是静态的,编译器应该进行这种静态优化,否则将其保留为运行时解析的 printf 函数。我认为使用可变格式是一个相当常见的用例。【参考方案2】:

这是为了性能。 printf 宏采用常量格式字符串(例如"Hello %d\n")并为该字符串生成优化代码。

【讨论】:

以上是关于在 Julia 中,为啥 @printf 是宏而不是函数?的主要内容,如果未能解决你的问题,请参考以下文章

在macro_rules中使用另一个宏而不需要生锈的“extern crate”

为啥 evbuffer_add_printf 只接受静态变量而不接受“动态”变量?

为啥在 Julia 中尝试使用 ggplot 时出现错误?

为啥 Julia 代码性能比 Fortran 低很多?

为啥 ArrayFloat64,1 不是 Julia 中 ArrayReal,1 的子类型?

为啥在C语言中,“scanf”竟然可以作为自定义函数的函数名而不报错??