您的位置:首页 > 编程语言 > C语言/C++

【C语言复习(十)】#error与#warning、#line、#与##的简单使用

2014-06-12 21:13 183 查看

1、#error的用法

#error编译指示字用于生成一个编译错误消息,并让预编译器停止编译,这个错误消息是开发人员自定义的。

用法:#error Message (Message不需要用双引号引起来)

2、#warning的用法

#warning编译指示字用于生成一个编译警告,输出到编译器的消息窗口,当编译器不会停止编译。

用法:#warning Message (Message不需要用双引号引起来)

示例:

#include <stdio.h>
int main()
{
#ifndef COMMAND
#warning Compilation will be stoped ...
#error No defined Constant Symbol COMMAND
#endif
printf("%s\n",COMMAND);
return 0;
}


首先,我们试着用命令行预编译一下:



如上所示,没有定义COMMAND宏,警告和错误消息都被显示出来了。

预编译时使用-D选项定义COMMAND宏:



可以看到编译成功,没有任何错误提示!

最后,编译成可执行文件,运行一下试试:



可以看到,顺利编译并运行了。

关于编译选项-D的说明:

gcc -D ..... 这个命令用来在编译时定义宏,可以给宏指定值,等效于我们在代码中直接定义宏,使用格式如上图,值得说明的是,这里面输入的引号、空格都使用的是C中的转义符,\40是用八进制表示的值为32的空格字符。

-D 参数在实际开发中还是经常使用的,比如可通过定义不同的宏,实现选择性编译,编译时定义不同的宏就编译相对应的代码。

3、#line的用法

#line编译指示字用于强制指定新的行号和编译文件名,并对源程序的代码重新编号,本质上#line编译指示字是对__LINE__和__FILE__内置宏的重定义。

用法:#line number filename (filename可省略)

例如:

#include <stdio.h>
int main()
{
printf("行号:%d\n", __LINE__);
printf("文件名:%s\n", __FILE__);
printf("%s\n","定义#line编译指示字后...");
#line 14 "Hello.c"
printf("行号:%d\n", __LINE__);
printf("文件名:%s\n", __FILE__);
return 0;
}


运行结果:



即从定义#line指示字的下一行开始,行编号变为14,这个只是字很早以前所有的源代码都在一个文件中时会使用它,用来区分当前的代码时谁写的,原本属于哪个文件!结构化程序设计以后,很少使用了吧。

4、#运算符的用法

#运算符用在预编译时期,用于将宏参数转换为字符串,即是加上双引号。

例如:

#include <stdio.h>

#define COMMAND(x) #x

int main()
{

printf("%s\n", COMMAND(Hello world!));
printf("%s\n", COMMAND(100));
printf("%s\n", COMMAND(while));
printf("%s\n", COMMAND(return));

return 0;
}

预编译后:
int main()
{

printf("%s\n", "Hello world!");
printf("%s\n", "100");
printf("%s\n", "while");
printf("%s\n", "return");

return 0;
}


可以看到,传入的宏参数自动被转换成了字符串。

#运算符的妙用:

#include <stdio.h>

#define CALL(f, p)  (printf("Call function %s\n", #f), f(p))

int square(int n)
{
return n * n;
}

int f(int x)
{
return x;
}

int main()
{

printf("1. %d\n", CALL(square, 4));
printf("2. %d\n", CALL(f, 10));

return 0;
}


运行结果:



可以看到,运行结果中输出了当前调用的函数的名称,这是用函数实现不了的功能,如果用函数来实现,只能在程序中把要输出的函数名写死,没有使用宏这么通用便捷!

5、##运算符的使用

##运算符用于在预编译期粘连两个符号,增大了宏的使用灵活性!

示例:

#include <stdio.h>

#define NAME(n) name##n

int main()
{

int NAME(1);
int NAME(2);

NAME(1) = 1;
NAME(2) = 2;

printf("%d\n", NAME(1));
printf("%d\n", NAME(2));

return 0;
}


预编译后:

int main()
{

int name1;
int name2;

name1 = 1;
name2 = 2;

printf("%d\n", name1);
printf("%d\n", name2);

return 0;
}


可以看出,预编译时,宏参数n被替换,并和name连接成一个整体,然后整体替换NAME宏。

##运算符的妙用:

#include <stdio.h>

#define STRUCT(type) typedef struct _tag_##type type;\
struct _tag_##type

STRUCT(Student)
{
char* name;
int id;
};

int main()
{

Student s1;
Student s2;

s1.name = "s1";
s1.id = 0;

s2.name = "s2";
s2.id = 1;

printf("%s\n", s1.name);
printf("%d\n", s1.id);
printf("%s\n", s2.name);
printf("%d\n", s2.id);

return 0;
}


预编译后:

typedef struct _tag_Student Student;struct _tag_Student
{
char* name;
int id;
};

int main()
{

Student s1;
Student s2;

s1.name = "s1";
s1.id = 0;

s2.name = "s2";
s2.id = 1;

printf("%s\n", s1.name);
printf("%d\n", s1.id);
printf("%s\n", s2.name);
printf("%d\n", s2.id);

return 0;
}


这样使用它,相当于扩展了C语言,能用一种“新”的方式去定义结构体,高通以前就用过这种方式,可提高代码的可读性与可维护性!

看到预编译后的代码,可能会有疑问,可以在结构体定以前就对结构体使用typedef定义别名么?实际上是可以的,typedef关键字可以随意使用,只要被重定义的类型有被声明就行!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: