当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;
}
程序抛出编译时错误。但我不明白它是否是某种语言违规或宏扩展错误或其他原因。
答案 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.