2.3 宏定义常见错误解析

在前面讲解带参数的宏定义和不带参数的宏定义时,只是简单提示了使用宏的一些注意事项,并没有详细地分析,下面针对带参数的宏定义和不带参数的宏定义的注意事项进行讲解。

2.3.1 不带参数的宏

下面先通过一段代码来看看不带参数的宏定义中容易被忽略的地方。


include<stdio.h>

define INT_P int*

void main()

{

int i,j;

int a[9];

INT_P p;

for(i=0;i<9;i++)

{

a[i]=i+1;

}

for(j=0,p=a;p<a+9;p++)

{

printf("a[%d]=%d\t",j++,*p);

if(0==j%3)

printf("\n");

}

return;

}


运行结果:


a[0]=1 a[1]=2 a[2]=3

a[3]=4 a[4]=5 a[5]=6

a[6]=7 a[7]=8 a[8]=9


在上面的代码中,宏定义部分使用了#define INT_P int*,所以接下来定义整型指针时只需要使用INT_P定义一个整型指针即可。我们发现,使用这种方式定义的类型名更具可读性。接下用指针p来打印出数组中的每个元素,如果使用它来定义多个变量,就会出现问题。修改下上面的代码,使用INT_P来定义多个变量。


include<stdio.h>

define INT_P int*

void main()

{

int i,j;

int a[9];

INT_P p,p1;

for(i=0;i<9;i++)

{

a[i]=i+1;

}

for(j=0,p1=a;p1<a+9;p1++)

{

printf("a[%d]=%d\t",j++,*p1);

if(0==j%3)

printf("\n");

}

return;

}


在用INT_P定义整型指针p时多定义了一个p1,且没有使用整型指针p来打印数组a中的每个元素,而是把p1当成整型指针来用,使用p1来打印数组a中的每个元素,结果在编译的时候出错了。看看其中一条主要的错误提示信息:


error C2440:'=':cannot convert from'int[9]'to'int'


为什么会出现上面的错误呢?现在来分析下,错误提示p1是一个整型变量,并非我们想要的整型指针。我们进行一下宏扩展,将“INT_P p,p1;”扩展为“int*p,p1;”,这样就可以清晰地发现问题的所在了,原来,在p之后定义的p1并非我们想要的整型指针,而是一个整型变量。因此在使用宏定义来定义想要的类型时要注意,对没有把握的地方最好进行一下宏扩展,分析扩展开的代码。

当然,难免有读者会犯下面的这种错误。


include<stdio.h>

define N 10;

void main()

{

printf("N的值为:%d\n",N);

return;

}


编译运行的时候提出如下错误:


error C2143:syntax error:missing')'before';'

error C2059:syntax error:')'


进行一下宏扩展就会发现,在宏定义部分多了一个分号。将“printf("N的值为:%d\n",N);”扩展为“printf("N的值为:%d\n",10;);”,清楚地发现后面多了一个分号。

读者还要注意的一点是,不要在字符串中使用宏,如果宏名出现在字符串中,那么将把宏按照字符串来处理,例如:


include<stdio.h>

define STR"Hello World!"

void main()

{

char*STRING="This is a string!";

printf("字符串中的宏%s\n","STR!");

printf("字符串中的宏:STR和不在字符串中的宏:%s\n",STR);

printf("出现在字符串变量名中的宏:%s\n",STRING);

return;

}


运行结果:


字符串中的宏STR!

字符串中的宏:STR和不在字符串中的宏:Hello World!

出现在字符串变量名中的宏:This is a string!


从上面的运行结果可以发现,出现在字符串中的宏被编译器按照字符串来处理了,因此在使用宏时不能在字符串中使用宏,否则宏将被当成一般字符串来处理。