宏与静态内联?

use*_*084 6 c c-preprocessor

使用宏而不是静态内联方法有什么显着的好处吗?特别是,如何使用静态内联方法在调用链中进一步实现可变参数的传递,而这可以通过宏一步完成?

#define myprintf(fmt, args...) printf (fmt, args)
Run Code Online (Sandbox Code Playgroud)

这只是一个简单的示例,但我仍然很好奇是否有一种等效的方法可以使用静态内联而不使用 va_args 步骤来执行此操作。

编译器是否总是内联静态内联方法?它们的尺寸又如何呢?调用任意子方法怎么样?如果我使用多个宏,所有宏都会编译成单个表达式,因此编译器可能更容易优化。编译器是否总是足够聪明,可以将多个级别的静态内联调用转换为单个表达式?

abl*_*igh 6

使用宏而不是静态内联方法有什么显着的好处吗?

宏不进行类型检查,也不评估它们的参数,这带来了巨大的力量和巨大的危险。

所以(引用一个众所周知的例子)

#define MAX(a,b) (a>b)?a:b
Run Code Online (Sandbox Code Playgroud)

可能看起来是一个更好的主意

static inline int max(a,b) { return (a>b)?a:b; }
Run Code Online (Sandbox Code Playgroud)

因为它不需要int参数(即适用于支持该>运算符的所有类型),但除此之外

  • 它评估aorb两次(考虑MAX(a++,b++)
  • 它有可能出现运算符优先级问题

这就解决了第二个问题:

#define MAX(a,b) ((a)>(b)?(a):(b))
Run Code Online (Sandbox Code Playgroud)

如何使用静态内联方法在调用链中进一步实现可变参数的传递,而这可以通过宏一步完成?

C99 支持可变参数宏,并且对此gcc定义有(非标准)扩展。

实际上有两种格式:

#define debug(format, ...) fprintf (stderr, format, __VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)

其中__VA_ARGS__被可变参数元素替换;这是标准的C99。

gcc还提供:

#define debug(format, args...) fprintf (stderr, format, args)
Run Code Online (Sandbox Code Playgroud)

其中args可以代表多个参数。

在第一个公式中,使用gcconly ,您可以处理完全省略的参数,并使用粘贴宏运算符避免多余的逗号##,即:

#define debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)

没有基于标准的方法来实现这一目标。

[]编译器[总是]内联static inline方法吗?

不,编译器可以自由地做它想做的事。它可以内联它们,或者为每个编译单元生成一组目标代码。然而,至少在理论上,它可以对#define'd 宏执行相同的操作。编译器并不总是将多个级别的内联宏转换为单个表达式,因为即使是单个内联宏实际上也可能不是内联编码的;通常,编译器比程序员更聪明地确定这是否是一个好主意。