C中的宏观和功能冲突

时间:2010-02-19 13:16:54

标签: c function macros

当C中出现宏和功能冲突时会引发什么错误? 是宏处理器错误还是由于某些语言违规而发生此错误?

例如,在此代码中:

#include <stdio.h>
#define MAX(i, j) (i>j)? i : j

int MAX(int i, int j){
  return (i>j) ? i : j;
}

int main(){
  int max = MAX(5, 7);
  printf("%d",max);
  return 0;
}

程序抛出编译时错误。但我不明白它是否是某种语言违规或宏扩展错误或其他原因。

6 个答案:

答案 0 :(得分:11)

在预处理阶段,代码转换为:

int (int i>int j)? int i : int j{
  return (i>j) ? i : j;
}

int main(){
  int max = (5>7)? 5 : 7;
  printf("%d",max);
  return 0;
}

......正如任何人都知道的那样,这是一个非法的C代码。

(使用gcc,您可以使用-E选项查看文件的预处理版本。)

答案 1 :(得分:3)

其他人已经指出了问题,但没有给出任何解决方案。最好的方法是使用MAX作为内联函数。如果宏位于标题中,请将内联函数定义放在标题中。如果您仍希望使用宏(或使用不支持内联函数的旧C编译器),您可以这样定义函数:

int (MAX)(int i, int j){
    return (i>j) ? i : j;
}

这将防止令人不安的宏扩展并提供MAX作为外部功能。例如,这将使您能够将其地址分配给变量。

extern int (MAX)(int, int);
...
int (*max_func_ptr)(int, int);
...
max_func_ptr = MAX;

答案 2 :(得分:2)

您将收到编译器错误,因为在尝试编译之前将扩展宏。

这是一个非常讨厌的问题,并且没有真正的解决方案。因此,您应该尽可能避免定义无范围的,类似函数的宏,尤其是在广泛包含的标头中。像所有东西一样,它们都有它们的位置,但你需要注意不要过度使用它们。

答案 3 :(得分:2)

没有特别发生错误的错误。会发生什么是宏处理首先发生,所以在某种意义上宏定义不尊重名称空间 - 这是宏被认为是坏形式的主要原因之一,应该避免,除非作为最后的手段。请参阅此问题,以获取某个人完全有效地使用名称BitTest作为模板的情况的示例,因为其他人决定使用该名称创建一个宏来“别名”另一个名称:{{3} }

因此,在您的示例中,正如其他答案所提到的,一旦预处理步骤发生,您将最终得到类似以下代码段传递给C编译器代替您的函数定义:

int (int i>int j)? int i : int j{
  return (i>j) ? i : j;
}

这是无效的C,所以你会得到一个编译器错误(可能是GCC 3.4.5):

error: syntax error before "int"

或(来自MSVC 9):

error C2059: syntax error : 'type'

这真的没什么帮助,因为当你看到错误在你的编辑器中引用的那一行时,它仍然会是这样的:

int MAX(int i, int j){

看起来有效。

有几种技术可用于帮助避免此问题:

  • 对宏名称和宏名称使用全部大写;这是一个大致遵循的惯例,以使宏命名空间与用于其他事物的名称分开

  • 将不希望扩展为宏的名称放在一起(这仅适用于'类似函数的'宏)。如果您的示例编写如下:

    int (MAX)(int i, int j){
      return (i>j) ? i : j;
    }
    

    它不会导致宏观扩张。但是,我不认为人们经常这样做。我使用的一组实用程序例程使用这种技术来防止宏命名冲突,我经常会问到为什么所有的函数名都在parens中。另外几位编辑也对这些文件的功能导航感到困惑。

  • 避免使用宏;正如我所提到的,这是宏被认为是坏形式的一个原因。还有其他原因包括如果您没有在宏参数周​​围正确使用parens或者通过评估具有多次副作用的宏参数,它们很容易导致扩展形式产生错误或意外的表达。

    如果可以,请使用内联函数或函数模板。

答案 4 :(得分:1)

由于预处理器宏仅用于处理纯文本,因此这些冲突总是会导致编译时错误。

答案 5 :(得分:1)

首先进行预处理,因此第4行将成为:

int (int i>int j)? int i : int j

无效C.