考虑以下C代码。
#include <stdio.h>
#define foo(x) if (x>0) printf("Ouchn");
int main()
{
int a = 4;
int b = -3;
if(a>b)
foo(b) ;
else
printf("Arrg!n");
printf("thanksn");
return 0;
}
运行程序时,我会出现一个错误,说error: ‘else’ without a previous ‘if’
。当我们根据宏定义将foo(b)
替换为if (b>0) printf("Ouchn")
时,用牙套编写时,程序不应该转移到以下代码中吗?
if(a>b){
if(x>0){
printf("Ouchn");
}
}
else{
printf("Arrh!n");
}
printf("thanksn");
我不明白编译器为什么抱怨。该程序实际转移到了什么?
谢谢
不,它正在变成此代码:
if (a > b)
if (b > 0) printf("Ouchn");;
else
printf("Arrg!n");
请注意, ("Ouchn")
之后有两个分号。这就是打破代码的原因。else
遵循第二个分号,这是一个无效的语句,而不是在此之前的if
语句。原因是您在宏定义中有一个半圆柱,而另一个则称为宏。
我建议将类似功能的宏的语句放在自己的块中,就像这样的答案所暗示的那样。但这是一个普遍的建议,在这个具体示例中,最好完全没有宏。
问题是您的宏扩展到
if(a>b)
if (b>0) printf("Ouchn"); ;
else
printf("Arrg!n");
//...
,由于额外的 ;
,这与else
无法使用。(还可以将括号化的x
参数(#define foo(x) if ((x)>0) printf("Ouchn")
((。
如果您从宏中丢失了;
,则会得到不同的分析:else
将与Inner if
相匹配:
if(a>b){ /*braces inserted to show the interpretation*/
if (b>0) printf("Ouchn");
else printf("Arrg!n");
}
,虽然您可以通过用悬挂的else
#define foo(x) if ((x)>0) printf("Ouchn"); else
//a ; after the macro else would complete the `else` with an empty branch
使用此此功能,尤其是在其他if
-else
内部触发gcc
/clang
等编译器中的警告,当时编译-Wall
和类似选项时,最好的方法是与IDIOMATION
#define macro() do{/*macro_body*/}while(0)
在您的情况下
#define foo(x) do{ if ((x)>0) printf("Ouchn"); }while(0)
有些人喜欢始终使用if
/else
语句的复合语句(被{
}
包围(,尽管这也可以解决问题,但我觉得如果您制作类似于其他人的功能的宏强制风格。
我的建议是忽略有关 fix 该宏的任何建议完全。
几乎 no 在现代C中使用宏(实际上只是略微不超过哑巴的文本替换(的理由,除了有条件的汇编以外的任何其他内容。
- 价值型宏通常应该用枚举代替,因为它们更好地保留类型信息。
- 函数类型宏应该只是 be 函数,因为现代编译器如果需要的话,将它们内联的麻烦很小。
使用实际功能还解决了所有这些奇异的边缘案例,例如:
#define calc(x) x * x
:
int a = 7;
int b = calc(a + 1); // a + (1 * a) + 1, NOT (a + 1) * (a + 1)
如果您希望它可靠地工作,则需要宏是((x) * (x))
之类的东西,但是即使也会以更复杂的性能失败,例如b = calc(a++)
。
因此,简而言之,您的代码中应具有的内容是:
void foo(int x) {
if (x > 0)
printf("Ouchn");
}
如果您 do 需要能够使用函数宏 wherewhere (裸语句,在支撑的if-block中的语句,则在未支撑的if-block中的语句,支撑在语句等时,您必须求助于奇异的宏(确保#include <stdbool.h>
以访问false
(:
#define XYZZY(s) do {plugh(s);} while (false)
但是,我会强烈建议您首先使它们起作用。
在if
和else
块之后使用{ }
总是被认为是安全且良好的做法。
正确的是
if(a>b) {
foo(b) ; /* keep inside { } */
}
else {
printf("Arrg!n");
}
编写后不应将程序传输到以下代码中 带牙套?
不,编译器不会手动卷曲牙套。宏替换后gcc -E test.c
看起来像
int main()
{
int a = 4;
int b = -3;
if(a>b)
if (b>0) printf("Ouchn"); ; /* extra semicolon causes the issue */
else /* there is no if for this else block, previous one terminated by extra ; in above if */
printf("Arrg!n");
printf("thanksn");
return 0;
}
示例代码:
#include <stdio.h>
#define foo(x) if ((x)>0) printf("Ouchn") /* if condition was wrong.. instead of x use (x) */
int main(void)
{
int a = 4;
int b = -3;
if(a>b)
{ /* always keep curly braces even though there is only one statement after if */
foo(b);
}
else
{
printf("Arrg!n");
}
printf("thanksn");
return 0;
}
我建议定义宏,如下
#define foo(x)
do {
if((x) > 0)
printf("Ouchn");
} while(0)