【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关键字可以随意使用,只要被重定义的类型有被声明就行!
相关文章推荐
- 【C语言复习(五)】由++,--操作符的使用简单认识C编译器的“贪心法”编译机制
- 采用GTK进行简单聊天程序客户端的编写,使用C语言。
- C语言使用数组实现简单队列
- 关于#和##在C语言的宏中的使用
- C语言中预定义符 __FILE__, __LINE__, __FUNCTION__, __DATE__, __TIME__ 的使用演示
- 02、老徐教你学C语言基础篇2——C语言摩拳擦掌齐上阵(环境篇)——简单工程的创建与使用
- C语言 不定参数的简单使用
- SQLite数据库使用回调函数的简单C语言实例(摘自sqlite.org)
- 【C语言复习(八)】宏定义的使用与分析
- c语言编程之sglib库的简单使用
- 专题 18 Inline Assembly(在C语言中嵌套使用汇编)
- 俺使用的C语言面向对象范式(前言与第一节:一个简单类的封装)
- [笔记]C语言中预定义符 __FILE__, __LINE__, __FUNCTION__, __DATE__, __TIME__ 的使用演示
- Linux下使用socket传输文件的C语言简单实现
- C语言的freopen使用测试及C++的文件流简单使用
- 如何使用epoll? 一个C语言的简单例子 - asdfjkl210 - ITeye技术网站
- 通过一个简单C程序复习C语言知识
- Linux下使用socket传输文件的C语言简单实现
- 【C语言】关于宏定义中#和##符号的使用和宏定义展开问题
- 使用C语言实现二维,三维绘图算法(3)-简单的二维分形