#define参数之间的空格

时间:2013-02-24 11:54:50

标签: c++ c macros

我对#define参数中不应有空格的概念感到困惑。

我认为唯一的限制是我们不应该在宏名称和直接(括号之间留有空格。我对么?我不应该在()括号内放置空格吗?

以下符号是否正确

#define AVERAGE_NUMS( min_val, max_val ) ((min_val + max_val) / 2)

伙计们,我上面的#define C ++语句只是一个例子。我实际上在使用#define时关心空格。无论如何谢谢你的回答。

4 个答案:

答案 0 :(得分:6)

是的,这是对的。但是你应该将每个参数括在括号中

#define AVERAGE_NUMS( min_val, max_val ) (((min_val) + (max_val)) / 2)

以避免运算符优先级问题。

答案 1 :(得分:4)

你是正确的,宏名称和紧随的开放括号之间没有空格。其他地方的空格==很好。

注意用于宏参数的名称,如果你有一个名为同名的变量,你会发生奇怪的事情...例如在你的例子中你的论点是max_val,但您已在宏中键入Max_val,因此如果您遇到使用此宏的变量Max_val,则代码编译正常,但无法编译其他地方......

我个人总是在宏名称上有一个前缀_来帮助避免这种情况......但是纯粹主义者告诉我,下划线是保留的,不应该被使用,但是填充它们:)

答案 2 :(得分:3)

在C 中,当使用宏进行小型计算时,应始终将表达式中的每个参数放在括号中,例如:

#define AVERAGE_NUMS(min_val, max_val) (((min_val) + (max_val)) / 2)

宏的参数列表中的空格是可选的,因此它们不会“伤害”。正如您已经说过的那样,开头括号之前的空格会改变宏的含义:它将不带任何参数,并将其出现的内容替换为您想要作为参数列表的内容以及“表述”。

如果不将括号中的参数放在括号中,则可能会遇到奇怪的结果,因为运算符优先级可能会改变您的表达式。这是因为宏只是文本替换规则,因此不尊重编程语言(C)的任何内容。

失败的一个小例子(我承认,这是一个奇怪的例子,但是你还可以编写其他函数作为“正常”用法失败的宏):

AVERAGE_NUMS(1 << x, y)

使用宏定义,这将扩展为

((1 << x + y) / 2)           // Operator precedence:  1 << (x + y)

但是使用上面的宏定义,它将扩展为

(((1 << x) + (y)) / 2)       // Operator precedence:  (1 << x) + y

在C ++ 中,我强烈建议您不要使用宏,除非确实必须这样做。

计算两个数字的平均值而不需要指定类型的更好方法是使用模板方法:

template<typename T>
T average_nums(T min_val, T max_val) {
    return (min_val + max_val) / T(2);
}

如果您担心性能,您应该注意所有现代编译器都以与宏定义相同的方式处理这段代码,即它们内联代码。这意味着没有涉及函数调用,但表达式avg(a, b)(a + b) / 2取代。

这和宏之间的区别在于宏只是在预编译期间发生的文本替换,所以实际的编译步骤会看到(a + b) / 2而不是{{1} }。

答案 3 :(得分:3)

我相信1999年C标准的以下摘录涵盖了如何在宏中处理空格的问题,它们确实表明空格只不过是一个标记分隔符,除了我们区分对象的情况类似宏和类似函数的宏,基于宏名称和紧跟在它后面的空格之间是否有空格。

5.1.1.2翻译阶段

...

1.3 The source file is decomposed into preprocessing tokens and sequences of white-space characters (including comments). ... Each comment is replaced by one space character. New-line characters are retained. Whether each nonempty sequence of white-space characters other than new-line is retained or replaced by one space character is implementation-defined.

1.4 Preprocessing directives are executed, macro invocations are expanded, and _Pragma unary operator expressions are executed. ... All preprocessing directives are then deleted.

1.7 White-space characters separating tokens are no longer significant.每个预处理令牌都转换为令牌。由此产生的标记在语法和语义上进行分析并翻译为翻译单元。

...

6.4词汇元素

<强>语法

<强>令牌:

  • 关键字
  • 标识符
  • 常数
  • 字串文本
  • 标点

<强> preprocessing-token:

  • 头名
  • 标识符
  • PP-数
  • 字符常数
  • 字串文本
  • 标点
  • 每个非白色空格字符,不能是上述
  • 之一

<强>语义

... Preprocessing tokens can be separated by white space; this consists of comments (described later), or white-space characters (space, horizontal tab, new-line, vertical tab, and form-feed), or both. As described in 6.10, in certain circumstances during translation phase 4, white space (or the absence thereof) serves as more than preprocessing token separation. ...

6.10预处理指令

<强>语法

...

  • #define identifier replacement-list new-line
  • # define identifier lparen identifier-listopt ) replacement-list new-line
  • # define identifier lparen ... ) replacement-list new-line
  • # define identifier lparen identifier-list , ... ) replacement-list new-line

lparen:

a ( character not immediately preceded by white-space

6.10.3宏替换

<强>约束

3 There shall be white-space between the identifier and the replacement list in the definition of an object-like macro.

<强>语义

10表格

的预处理指令
  • # define identifier lparen identifier-listopt ) replacement-list new-line
  • # define identifier lparen ... ) replacement-list new-line
  • # define identifier lparen identifier-list , ... ) replacement-list new-line

定义带有参数的function-like宏,在语法上类似于函数调用。