C中宏的意外行为

时间:2013-09-20 18:12:39

标签: c macros

以下代码如何执行(除第二行中的分号外,代码相同)

此代码可以执行,也可以执行。

#include<stdio.h>
#define SWAP(a, b) int t; t=a, a=b, b=t  //note here is no semi-colon at the end
int main()
{
    int a=10, b=12;
    SWAP(a, b);
    printf("a = %d, b = %d\n", a, b);
    return 0;
}

但是预计不会运行以下内容,因为SWAP(a, b)将被int t; t=a, a=b, b=t;;替换。所以两个分号会产生错误!

#include<stdio.h>
#define SWAP(a, b) int t; t=a, a=b, b=t;  //note the semi-colon here
int main()
{
    int a=10, b=12;
    SWAP(a, b);
    printf("a = %d, b = %d\n", a, b);
    return 0;
}

4 个答案:

答案 0 :(得分:7)

杂散分号变为空语句,在C语言中完全合法。

您可以通过在代码中添加包含十几个分号的行来证明这一点。

另外,你的宏写得更好:

#define SWAP(a, b) do { int t = a; a = b; b = t; } while (0)

如果您尝试在单个代码块中进行两次不同的交换,这种方法会更好。

答案 1 :(得分:4)

如果在宏中使用,本地范围中的额外分号将永远不会在C(C99之后)中产生错误。他们只是简单地介绍一个空话。你在哪里知道这应该是一个错误?由于额外的分号,可以编造一个会触发“孤立的其他”错误的示例,但无论如何,您的宏在if下都无法使用(见下文)。

在C89 / 90中,有可能在声明后通过无意中放置的额外分号触发错误,因为在C89 / 90中混合声明和语句是非法的。例如

int a, b;;  /* <- A declaration followed by an empty statement */
int c;      /* <- ERROR: Illegal declaration after a statement */

但是在C99中这不是问题,因为声明和陈述可以混合在一起。您的SWAP显然已针对C99实施,因此不会立即应用此问题。

值得注意的是SWAP的这种实现非常糟糕且非常危险。它可能会导致意外,危险和完全无意义的行为,如

if (/* whatever */)
  SWAP(a, b);

更好地遵循do/while(0)惯用语并执行类似

的操作
#define SWAP(a, b) do { int t; t=a, a=b, b=t; } while (0)

注意 - 最后没有分号。

答案 2 :(得分:2)

一个半冒号本身就是一个“空声明”,一个什么都不做的声明。

它有时很有用,但大部分时间都是错误的。例如,这个if语句没有预期的效果:

if (x == y);
{
    z=1;
}

尽管如此,它仍然是C语言中非常有效的部分。

答案 3 :(得分:2)

使用后

gcc -E file_name.c您将获得第二个代码: -

int t; t=a, a=b, b=t;;

是有效的

,相当于

int t; t=a, a=b, b=t;

; // null statement does nothing