巴基斯坦人做网站怎么样,重庆动画网站建设,厦门建设局官网,律师网站建设建议1.预处理符号
C语言中设置了一些预定义符号#xff0c;可以直接使用#xff0c;预定义符号是在预处理期间处理的。
__FILE__//代表当前进行编译的源文件
__LINE__//文件当前行号
__DATE__//文件当前日期
__TIME__//文件当前时间
__STDC__//如果编译器遵循ANSIC#xff0c;…1.预处理符号
C语言中设置了一些预定义符号可以直接使用预定义符号是在预处理期间处理的。
__FILE__//代表当前进行编译的源文件
__LINE__//文件当前行号
__DATE__//文件当前日期
__TIME__//文件当前时间
__STDC__//如果编译器遵循ANSIC其值为1否则未定义
接下来我们可以试验一下
#includestdio.hint main()
{printf(%s\n,__FILE__);printf(%s\n,__DATE__);printf(%s\n,__TIME__);printf(%d\n,__LINE__);return 0;
}
经过预处理之后代码变成了
int main()
{printf(%s\n,test.c);//目前在编译的文件名printf(%s\n,July 19 2024);printf(%s\n,18:17:54);printf(%d\n,8);return 0;
} 2.#define定义字符常量
基本语法 #define 名字 内容
即 #define name stuff
例子
#define MAX 1000
#define reg register//为register这个关键字创了一个简短的名字
#define do_forever for(;;)//变成死循环了
#define CASE break;case//在写case语句时自动把break写上
//如果定义的语句过长可以分成几行写除最后一行外每行最后都要加上一个反斜杠\(续行符)。注意其后不能有空格应直接回车否则续的就不是原来的语句了。
#define DEBUG_PRINT printf(file:%s\tline:%d\t\date:%s\ttime:%s\n,\__FILE__,__LINE__, \__DATE__,__TIME__) 思考
在define定义标识符的时候如果在末尾加上‘’怎样
比如
#define MAX 1000
#define MAX 1000;
建议不要加‘’因为可能会导致一些问题。
例
当用了
printf(%d\n,MAX);
就会出问题。
如果是这个
if(condition)maxMAX;
elsemax0;
那么等替换之后if和else之间就是两条语句而没有大括号时if和else后面只能接一条语句else就不知道是和哪个else匹配的就会出现语法错误。
3.#define定义宏
#define机制包括了一个规定允许把参数替换到文本中这种实现通常称为宏(macro)或者定义宏(define macro)。
下面是其
定义方式
#define name(parament-list) stuff
其中的parament-list是一个由逗号隔开的符号表带表参数它可能出现在stuff中。
注意 参数列表的左括号必须与name紧邻如果二者之间有任何的空白存在参数列表就会解释为stuff的一部分。
举例
#define f(x) x*x
4.带有副作用的宏参数
所谓的副作用就是在实现预想的结果的同时影响了其他的结果。
当宏参数在宏的定义中出现超过一次的时候如果参数带有副作用那么你在使用这个宏的时候就可能出现危险导致不可预料的后果。
例如
#define MAX(a,b) ((a)(b)?(a):(b))
.....
int x5;
int y8;
int zMAX(x,y);
5.宏替换的规则
在程序中扩展#define定义符号和宏时需要涉及几个步骤。
1.在调用宏时首先对参数进行检查看看是否包含任何由#define定义的符号。如果是他们首先被替换。
2.替换的文本随后被插入到程序中原来文本的位置。对于宏参数名被他们的值替换。
3.最后再对结果文本进行扫描看看它是否包含任何由#define定义的符号。如果是则重复上述处理过程。
注意
1.宏参数和#define定义中可以出现其他#define定义的符号。但是对于宏不能出现递归。
2.当预处理器搜索#define定义的符号时字符串常量的内容并不被搜索。
例
#define M 10
但是“MARY中的M是不会被替换的。
6.宏与函数的对比
宏通常被应用于执行简单的运算。
比如在两个数中找到较大数。
#define MAX(a,b) ((a)(b)?(a):(b))
而如果用函数来完成有一下缺点
1.用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间要多。所以在小型计算中宏比函数在程序的规模和速度上要更胜一筹。
2.更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使用反之宏可以适用于整型长整型浮点型等可以用来比较大小的类型。宏的参数是类型无关的。
宏有些时候可以做到函数做不到的事。比如宏的参数可以出现类型而函数不可以
#define MALLOC(num,type) (type*)malloc(num*sizeof(type))
和函数相比宏的劣势
1.每次使用宏时一份宏定义的代码将插入到程序中。除非这段代码较短否则可能大幅度增加程序的长度。
2.宏没法调试
3.宏由于是类型无关的不够严谨。
4.宏可能带来运算符优先级的问题导致程序容易出错。
至于第四点有个例子
#define MAX(a,b) a*b
//当a31 b12时
7.#和##
一.#
#运算符将宏的一个参数转换为字符串常量。它仅允许出现在带参数的宏的替换列表中。
‘#运算符所执行的操作可以理解为“字符串量化”。
适用场景
当我们想要打印出“The value of x is %d的情况
例如
The value of b is 12
The value of a is 1
而以上的语句大致相同需要改变的是某个数据的名字以及数据的具体大小。
为了方便后面的讲解我们需要补充一个知识点
在c语言中printf(Hello world!)与printf(Helloworld!”)的结果是一样的。
回到原来的问题我们把这个语句定义为宏
即
#define PRINT(n) printf(The value of#xis%d\n,x);
当我们使用这个宏时
int a1;
PRINTF(a);
就会变成
The value of a is 1
而#x就是将x转化为x这个字符串。
如果还想在字符串中加一些内容可以直接#内容。
注意我们需要使用这个符号的一个原因是宏在替换时不会替换字符串内的内容。
二.##
##字符用在宏定义里可以把两个符号粘连在一起合成一个符号。被称为记号粘合。
这样的连接产生的标识符必须是合法的否则就是未定义的。
它有如下应用场景
当我们想要找出两个数中的较小数时不同的数据类型得写不同的函数但是这样的函数结构是类似的于是我们就想到用宏然而这些不同函数的名称也要随着参数改变同时要是合法的而宏的参数只有一个那就是类型所以我们想到用记号粘合。
int int_max(int x,int y)
{return xy?x:y;
}
float float_max(float x,float y)
{return xy?x:y;
}
改法
#define TYPE_MAX(type) \
type type##_max(type x,type y)\
{ \return (xy?x:y); \
}
具体使用
TYPE_MAXint)
//在预编译中替换为
//int_max(int x,int y)
//{
// return xy?x:y;
}
TYPE_MAX(float)
//在预编译中替换为
//float float_max(float x,float y)
//{
// return xy?x:y;
//}int main()
{int mint_max(2,3);float nfloat_max(3.5f,4.5f);return 0;
}
8.命名约定
由于宏与函数的使用语法相似所以语言上无法帮我们区分二者所以我们通常用一下命名习惯区分
1.宏的全名全部大写。
2.函数名不要全部大写。
当然这个规定不一定要遵守c语言本身就有一些没有遵守例如
offsetof———宏计算结构体成员相较于结构体起始位置的偏移量。
9.#undef
这个指令用于移除一个宏定义。是可以直接写入主函数的,不过需要注意的是它与#define相同不用单独加;来表示语句的结束。
例如
#define NAME 10int main()
{#undef NAMEreturn 0;
}
10.命令行定义
许多编译器提供了一种能力允许在命令行中定义符号用于启动编译过程。
例如当我们根据同一个源文件要编译出一个程序的不同版本时这个能力就能起到作用。
假如某个程序中声明了一个某长度的数组如果机器的内存有限我们需要一个很小的数组但是另一个机器的内存大些我们需要一个更大的数组时就可以利用这个能力。
好处代码可以根据需求快速调整。
11.条件编译
利用条件编译指令我们可以很方便的编译或放弃一条或一组语句。
例如某些语句起到的是调试作用我们希望在某些条件下使用。
#define _DEBUG_//当不想要ifdef后面的语句时就注释掉这句int main()
{#ifdef _DEBUG_printf(6\n);#endifreturn 0;
}
常见的条件编译指令
#if 常量表达式 //如果为假后面的语句就不参与编译//...
#endif
//注意一定要以#endif结尾//多分支条件编译#if 常量表达式//...
#elif 常量表达式//...
#else//...
#endif//判断是否被定义
#if defined(symbol)
#ifdef symbol#if !definede(symbol)
#ifndef symbol
注意这些指令是可以相互嵌套的
12.头文件的包含
一.本地文件的包含
#includefilename
查找方式先在源文件下的目录里找如果该文件未被找到编译器就会像找库函数一样在标准位置查找头文件。
如果找不到就显示编译错误。
二.库文件包含
#includefilename
查找方式直接在标准文件下查找如果找不到就提示编译错误。
当然库文件也可以用包含不过这样的话效率就会低一些也会没那么容易区分本地文件和库文件。
三.嵌套文件的包含
如果一个同文件被多次包含编译器在预处理时就会多次替换头文件的内容这样的重复包含对编译的压力很大。所以我们可以使用一些方法避免这样的情况出现。
利用条件编译防止重复包含。
方法一
在每个头文件里加上
#ifndef __TEST_H__
#define __TEST_H__
//头文件中的内容
#endif
方法二
在每个头文件中加上
#pragma once 13.其他预处理指令
目前不想写了可参考《C语言深度剖析》这本书。