【问题标题】:macro and function conflict in CC中的宏和函数冲突
【发布时间】:2011-01-18 18:47:51
【问题描述】:

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;
}

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

【问题讨论】:

  • 除了明显的问题(你是自虐狂吗?),它吐出了什么错误?而且,您是否尝试过用括号括住宏?
  • 另外,请注意,MAX 的这个宏定义具有潜在的危险性和混淆性,因为它会对其参数进行两次评估(例如,考虑评估 MAX(i++,j++) 会发生什么)
  • Rule numero uno:用大写写你的宏名,用小写写函数名。问题解决了。

标签: c function macros


【解决方案1】:

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

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 选项查看文件的预处理版本。)

【讨论】:

    【解决方案2】:

    其他人指出了问题,但没有给出解决方案。最好的办法是只使用 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;
    

    【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      没有发生专门指出存在冲突的错误。发生的情况是宏处理首先发生,因此从某种意义上说,宏定义不尊重名称空间 - 这是宏被认为是错误形式的主要原因之一,除非万不得已,否则应避免使用。有关以下情况的示例,请参阅此问题,其中某人完全有效地使用名称 BitTest 作为模板被搞砸了,因为其他人决定使用该名称创建一个宏来“别名”另一个名称:Win32: BitTest, BitTestAndComplement, ... <- How to disable this junk?

      因此,在您的示例中,正如其他答案所提到的,一旦发生预处理步骤,您最终会得到类似于以下 sn-p 的东西被传递给 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;
        }
        

        它不会导致宏扩展。但是,我不经常看到人们这样做。我拥有的一组实用程序例程使用这种技术来防止宏名称冲突,并且我经常会收到关于为什么所有函数名称都在括号中的问题。还有一些编辑器对这些文件的功能导航感到困惑。

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

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

          预处理首先发生,所以第 4 行将变为:

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

          这不是有效的 C.

          【讨论】:

            猜你喜欢
            • 2010-11-26
            • 2019-05-16
            • 1970-01-01
            • 2012-06-19
            • 1970-01-01
            • 1970-01-01
            • 2015-10-23
            • 2018-06-10
            相关资源
            最近更新 更多