编译
C语言程序的编写经过四个过程
编辑、编译、运行、调试。从编译环节到到生成可执行文件需要经过四个步骤:
预处理:展开宏和头文件,将注释用空格替代,过滤掉无用的条件编译代码。最终生成一个没有宏定义,没有条件编译指令,没有特殊符号的文件(.i文件)。预处理的指令为:gcc -E main.c -o main.i
编译:编译过程指的是将高级语言(C语言、python等语言)转换为汇编语言文件(.s文件)。
汇编:汇编过程是将汇编文件转换为机器代码文件(.o文件)。
链接:将使用到的文件链接到一起,生成最终可执行文件。
预处理
预处理包含对宏定义、条件包含和条件编译的操作。
宏定义
宏的语法为 "#define 标识符 字符串"。
//宏定义
#define PI 3.14
一般将宏名大写,用以区分常规变量。预处理实质是将字符串以外的宏名用宏值进行原样替换。
#undef:取消宏定义,用于结束宏生命周期,只有在作用域#define和#undef之间的宏名才会被原样替换。
代码示例:
#define PI 3.14
int r = 4;
float s = PI * r * r;
float c = PI * r * 2;
//定义一个宏用来表示圆周率,可以供不同运算使用
带参宏定义
带有参数的宏,实质上依然为原样替换。语法为 ”#define 宏名(参数) 宏值“
//带参宏定义
#define SUM(a,b) a+b
带参宏会在原样替换时会把参数一同替换,带参宏预处理时不会考虑运算优先级,为了防止出现优先级错误,建议在定义时将所有参数用小括号包围。
带参宏又被叫做宏函数,但区别于函数,函数本质是代码的调用,且带参宏不检查语法错误。
代码示例:
#include <stdio.h>
#define ADD(a,b) a+b
#define MINU(a,b) a-b
#define PLUS(a,b) a*b
#define DIV(a,b) a/b
int main(void)
{
int x,y;
scanf("%d %d",&x,&y);
printf("%d + %d = %d\n",x,y,ADD(x,y));
printf("%d - %d = %d\n",x,y,MINU(x,y));
printf("%d * %d = %d\n",x,y,PLUS(x,y));
printf("%d / %d = %d\n",x,y,DIV(x,y));
return 0;
}
注意:上述宏定义和带参宏的原样替换都发生在预处理阶段,宏经过预处理被字符进行替换,但直到运行时值才会经过运算。且如果不使用续行符宏需要写在一行。
文件包含
文件包含一般指头文件的包含。有两种形式:
#include <头文件>和#include "头文件"
两种包含方式区别在在于使用”<>“时,预处理阶段会在系统默认路径下查找头文件;使用” "" “时系统会在当前目录下进行查找,如果没有找到再回默认路径下查找。
条件编译
条件编译有三种形式:
#ifdefine 标识符
程序段1
#else
程序段2
#endif
当标识符为真时保留程序段1,为假时保留程序段2。
#ifndef 标识符
程序段1
#else
程序段2
#endif
当标识符为假时保留程序段1,为真时保留程序段2。
#if 表达式
程序段1
#else
程序段2
#endif
当表达式为真时保留程序段1,为假时保留程序段2。通常简写为#if 0、#endif用于代码调试。
头文件
头文件的编写常规规则:
#ifndef _STDIO_H_
#define _STDIO_H_
---头文件内容---
#endif
在初始位置判断是否已经包含,如果没有包含则定义一个宏,在后续多个文件调用同一个头文件时防重复定义。
指针
指针基础
指针概念:是内存单元的编号,也是地址。是一种专门用来处理地址的数据类型
语法
基类型 * 指针变量名
int *p; //int *是数据类型;p是变量名;
int a = 10;
int *p = &a;
//取a的首地址,存放在p中
理解:指针变量中存放目标变量的地址,可以称为指针指向目标变量。
基类型:几大数据类型。用来表示存放的地址所指向的变量的类型。基类型要与指向空间的数据类型匹配。
*:在定义时表示定义的变量p是指针类型的变量;作为指针运算符时,只能对指针进行运算。表示间接访问指针指向的基类型的内存空间。
将定位到指针中的地址,偏移出基类型大小(sizeof int...)的空间,把偏移出的空间当作一个基类型,把地址指向的变量的数据填入偏移出的空间,实现间接访问。(直接访问:直接对参数的数值进行操作;间接访问:通过获取地址,将值读取后)
代码示例:
在定义时*表示变量为指针类型。在使用时*表示间接访问被指向的空间的数据。
#include <stdio.h>
int sum(int *i,int *j) //形参接受数据类型为指针
{
int sum;
sum = *i + *j; //计算时间接访问取数值进行运算
return sum;
}
int plus(int *i,int *j)
{
int plus = *i * *j;
return plus;
}
int main(void)
{
int a,b;
printf("Input two numbers:\n");
scanf("%d %d",&a,&b);
int *i,*j; //定义指针变量
i = &a;
j = &b; //取地址交给指针变量,间接读取数值
int sum0 = sum(i,j); //只传递指针(地址)
int plus0 = plus(i,j);
printf("%d\n",sum0);
printf("%d\n",plus0);
return 0;
}