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