c语言 - "else",在用参数定义宏时没有以前的"if"错误



考虑以下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)

但是,我会强烈建议您首先使它们起作用。

ifelse块之后使用{ }总是被认为是安全且良好的做法。

正确的是

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)

最新更新