C语言——预处理

C语言专题之预处理篇

C语言——预处理

#error

1
2
3
4
5
6
7
8
// 编译程序时,只要遇到#error就会生成一个编译错误提醒,并且停止编译,
语法格式:
#error error-message
实例:
#ifdef xxx
#error “xxx has been defined”
#else
#endif

#ifndef #define #endif

1
2
3
4
// 当项目中有多个c文件使用到同一个头文件是,在编译的时候会出现大量的变量,函数声明冲突,解决就是使用
#ifndef _HEAR_H_
#define _HEAR_H_
#endif

#define和const

Define和const 都可以用于定义常量但以下区别(生效时间,内存占用情况,类型检查):

  1. define只是单纯的文本替换,define常量的生命生命周期止于编译器,不存在分配内存,存在与程序的代码段
  2. const生效于编译的阶段;define生效于预处理阶段
  3. Const修饰的常量处于程序的数据段,在堆栈中分配空间
  4. Const有数据类型检查,define没有
  5. #define不可调试,const能调试
  6. const定义的变量在C中不是真正的常量
  7. Const 定义的常量不能作为数组的大小

typedef和#define

原理不同:

  1. 首先#define是预处理命令,在预处理阶段只是机械的替换带入字符串,并不会左类型检查,
  2. typedef是关键字,作用是给自己的作用域内给一个已经存在的类型起个别名
  3. #define没有作用域的限制,只要是之前预定义过的宏,在以后的程序中都可以使用,而typedef有自己的作用域
  4. 对指针的操作不同

#define

表明一年

1
#define YEAR (60 * 60  * 24 * 365)ul

标准宏MIN

1
#define MIN(a, b) ((a) < (b) ? (a) : (b))

缺点

  1. 无法进行类型检查
  2. 运算优先级问题
  3. 无法调试
  4. 代码膨胀
  5. 无法操作类的私有数据成员
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#define m(a,b) a*b
// #define m(a,b) (a)*(b)//避免出问题最好加上()
int main()
{

    printf("%d\n",m(5,6));
    printf("%d\n",m(5+1,6));//实际是这样的:5+1*6
    return 0;
}

#define sqort(a)  ((a)*(a))
// 实例1: 
int a = 5;
int b = sqort(a++);//( (a++) * (a++) )  先给括号赋值 5之后a再+1=6
printf("%d\n",b);//30
printf("%d\n",a);//7

// 实例2:	
int a = 5;
int b = sqort(++a);//((++a)* (++a)) 
printf("%d\n",b);//49
printf("%d\n",a);//7

这里主要是考察++a和后加加的问题
// 记住一点:
++a返回的a的引用a++返回的是a加之前的数值
a的引用是要等最终的那个a才能确定的

#include

对于.#include<头文件>,表示是系统文件,编译会先从标准库路径下搜索,编译器设置的头文件路径–>系统变量

对于#include”头文件”,当前头文件目录–>编译器设置的头文件路径–>系统变量

C代码编译过程

  1. 预处理(Preprocessing):
  • 预处理阶段是在实际编译之前的一个可选步骤,用于处理源代码中的预处理指令,比如 #include#define
  • 预处理器将处理这些指令,并且可能会包含其他文件、进行宏替换等。
  • 预处理的输出是一个经过处理的源文件,通常以.i.ii为扩展名。
  1. 编译(Compiling):
  • 编译阶段将预处理后的源代码转换为汇编代码(Assembly Code)。
  • 编译器(如GNU Compiler Collection中的gcc)将C源代码翻译成汇编语言。
  • 输出是一个以.s为扩展名的汇编代码文件。
  1. 汇编(Assembling):
  • 汇编阶段将汇编代码转换为机器语言指令。
  • 汇编器(如GNU Assembler中的as)将汇编代码翻译成机器码。
  • 输出是一个以.o.obj为扩展名的目标文件,包含了二进制指令。
  1. 链接(Linking):
  • 链接阶段将多个目标文件(例如,多个C文件分别编译得到的目标文件)合并为一个可执行文件。
  • 链接器(如GNU的ldgcc中的链接器部分)将各个目标文件中的函数和变量引用解析,并创建一个可执行文件。
  • 链接的输出是一个可执行的二进制文件,可以在操作系统上运行。

在头文件中是否可以定义静态变量

不可以,因为静态变量是有记忆的,不会随函数结束而结束,所以,如果定义在头文件中,那么就会被多个文件开辟空间,浪费资源或者重新出错

#和##的作用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// #利用宏参数字符串化
#define ARGV(x) printf(""#x" is %s\n",#x) //表示把参数x解释为字符串
int a = 5;
ARGV(a); //a is a

// ##运算符粘合剂 组合成一个变量,强制分隔
#define targ( n )   X##n   //表示X1......或Xn
int main()
{
   int a = 5;
   // ARGV(a);
   int targ(1) = 10;//表示 X1 =10
   printf("%d\",X1);//10
   return 0
}
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy