c语言学习笔记---预编译
专题三:
1) 预编译
处理所有的注释,以空格代替,
将所有的#define删除,并且展开所有的宏定义,
处理条件编译指令#if,#ifdef,#elif,#else,#endif
处理#include,展开呗包含的文件,
保留编译器需要使用的#pragma指令,
预处理指令:gcc-E file.c –o hello.i
编译:
对于处理文件进行一系列词法分析,语法分析和语义分析
语法分析主要分析关键字,表示符,立即数是否合法,语法分析主要分析表达式是否遵循语法规则
语义分析子啊语法分析的基础上进一步分析表达式是否合法
分析结束后进行代码优化生成相应的汇编代码文件
编译指令:gcc –s file.c –o hello.s
汇编:汇编器将汇编代码转变为机器可以执行的指令,
每个汇编句几乎都对应一条机器指令
汇编指令:gcc –c file.s –o hello.o
链接器的意义
连接器的主要作用是各个模块之间相互引用的部分处理好,
使得各个模块之间能够正确的衔接。
模块拼装: 静态链接,(file1.o,file2.o,libc.a)-à链接器(linker)-àa.out
动态链接:file1.cà编译器(gcc)àfile1.oà连接器(linker)àa.out
Lib1.soàstub1à连接器(linker)àa.out
Lib2.soàstub2à链接器(linker)àa.out
编译器将编译工作主要分为预处理,编译和汇编三部
连接器的工作是各个独立的模块链接为可执行程序,
静态链接在编译期完成,动态链接在运行期完成,
2)宏定义与使用分析:
定义宏常量:
#define定义宏常量可以出现代码的任何地方
#define从本行开始,之后的代码都可以使用这个宏常量
#define ERROR -1
#define PI 3.1415926
#define PATH_2 “D:\Delphi\C\Topic3.ppt”
#define PATH_1 D:\Delphi\C\Topic3.ppt
#define PATH_3 D:\Delphi\c\
Topic3.ppt
顶哟宏表达式
#define 表达式给有函数调用的假象,却不是函数,
#define表达式可以比函数更强大
#define 表达式比函数更容易出错
#define SUM(a,b) (q)+(b)
#define MIN(a,b) ((a)<(b)? (a):(b))
#define DIM(a) () (sizeof (a)/sizeof(*a))
以上宏表达式有没有问题?完全等价函数吗?
宏表达式与函数的对比
宏表达式在预编译期被处理,编译器不知道宏的存在,
宏表达式用”实参”完全替代形参,不进行任何运算,
宏表达式没有任何的调用的开销
宏表达式不能出现定义
#define FAC(n) ((n>0)? (FAC(n-1)+1):0)
Int j=FAC(100);
宏定义的常量或表达式是否有作用或限制
Int f1(int a, int b)
{
#define MIN(a,b) ((a)<(b)?a:b)
Return MIN(a,b);
}
Int f2 (int a,int b,int c)
{
Return MIN (MIN(a,b),c);
}
Int main ()
{
Printf (“%d\n”,f1(2,1));
Printf(“%d\n”,f2(5,3,2));
Return 0;
}
强大的内置宏,
_FILE_------被编译的文件名-----file1.c
_LINE_------当前行号---25
_DATE_-------编译时的日期------Jan 31 2012
_TIME_ -------编译时的时间 ----17:01:01
_STDC_ -------编译器是否遵循标准C规范—1
定义日志宏
#define f(x) ((x)-1)
上面的宏定义代表什么意思
宏定义对空格没敢吗?宏”调用”对空格敏感吗?
条件编译使用分析
条件编译的行为类似于C语言中的if…else
条件编译是预编译指示命令,用于控制是否编译某段代码
#define c1
Int main()
{
#if(c==1)
Printf(“This is first printf …\n”);
#else
Printf(“This is second printf …\n”);
#endif
Return 0;
}
#include 的困惑
#include 的本质将已经存在的文件内容嵌入到当前文件中,
#include的间接包含同样会产生嵌入文件内容的动作
条件编译的意义
条件编译使得我们可以按不同的条件不同代码段,因而可以产生不同的目标代码
#if…#else…#endif被预编译器处理;而if…else语句被编译器处理,必然被编译进目标代码
实际工程条件编译主要用于一下两种情况:
不同的产品线共用一份代码
区分编译产品的调试版和发布版
总:小结
条件编译的使用:
通过编译器命令行能够定义预处理器使用的宏
条件编译可以避免重复包含头同一头文件,
条件编译是在工程开发中可以区别不同产品线的代码,
条件编译可以定义产品的发布版和调试版
#error的用法:
#error用于生成一个编译错误的消息,并停止编译;
用法:#error message 注:message 不需要用双引号围,
#error编译指示字用于自定义程序员特有的编译错误消息类似的,#warning 用于生成编译警告,但不会停止编译。
#error 和 #warning的使用:自定义错误消息
#line的用法:
#line用于强制指定新的行号和编译文件名,并对源程序的代码重新编号
用法:
#line number filenames 注:filename 可省略
#line 编译指示字的本质是重定义_LINE_和_FILE_
#pragma预处理分析:#pragma是编译器指示字,用于指示编译器完成一些特定的动作,
#pragma 所定义的很多指示字是编译器和操作系统特有的,
#pragma 在不同的编译器间是不可移植的
预处理器将忽略它不认识的#pragma指令,
两个不同的编译器可能以两种不同的方式解释同一条#pragma指令,
一般用法:#pragma parameter 注:不同的Parameter参数语法和意义 各不相同的
#pragma message :
message参数在大多数的编译器中都有相似的实现,
message参数在编译时输出消息到编译输出窗口中,
message可用域代码的版本控制,注:message是VC特有的编译器指示字,GCC中将其忽略。
#pragma 在不同编译器下的使用示例:
#pragma pack
什么是内存对齐?
不同类型的数据在内存中按照一定的规则排列;而不是数序的一个接一个的排放,这就是对齐
struct Test1
{
char c1;
short s;
char c2;
int i;
}
struct Test2
{
char c1;
char c2;
short s;
int i;
}
两种类型所占的内存空间是否相同?
#pragma pack
为什么需要i内存对齐?
cpu对内存的读取不是连续的,而是分成块读取的,块的大小只能是1、2、4、8、16字节
当读取操作的数据未对齐,则需要两次总线周期来访问内存,因此性能会大打折扣。
某些硬件平台只能从规定的地址处去某些特定类型的数据,否则抛出硬件异常。
#pragma pack
#pragma pack 能够改变编译器的默认对i去方式
#pragma pack (2) #pragma pack(4)
struct Test1 struct Test2
{ {
char c1; char c1;
short s; char c2;
char c2; short s;
int i; int i;
} }
#pragma pack () #pragma pack()
sizeof(struct Test1)=?
sizeof(struct Test2)=?
#pragma pack:
struct 占用的内存大小
第一成员起始于0偏移处,
每个成员按其类型大小和指定对齐参数n中较小的一个进行对齐,
偏移地址和成员占用大小均需对齐
结构体成员的对齐参数为其所有成员使用的对其参数的最大值
结构体总长度必须为所有对齐参数的整数倍,
课后思考:
结构体变量是否可以直接用memcmp函数进行相等判断?为什么?
#和##晕窜使用解析:
#运算符:
#运算符用于在预编译期将宏参数转为字符串
#include <stdio.h>
#define CONVERS(x) #x
int main ()
{
printf ("%s\n",CONERS(Hello world!));
printf ("%s\n",CONVERS(100));
printf ("%s\n",CONVERS(while));
printf("%s\n",CONVERS(return));
return 0;
}
#运算符在宏中的妙用:
## 运算符:
##运算符用于在预编译期粘连两个符号
#include<stdio.h>
#define NAME (n) name##n
int main()
{
int NAME (1);
int NAMR(2);
NAME (1)=1;
NAME(2)=2;
printf ("%d\n",NAME(1));
printf("%d\n",NAME(2));
return 0;
}
利用##定义结构类型:
c语言学习笔记---预编译的更多相关文章
- HTML语言学习笔记(会更新)
# HTML语言学习笔记(会更新) 一个html文件是由一系列的元素和标签组成的. 标签: 1.<html></html> 表示该文件为超文本标记语言(HTML)编写的.成对出 ...
- 2017-04-21周C语言学习笔记
C语言学习笔记:... --------------------------------- C语言学习笔记:学习程度的高低取决于.自学能力的高低.有的时候生活就是这样的.聪明的人有时候需要.用笨的方法 ...
- 2017-05-4-C语言学习笔记
C语言学习笔记... ------------------------------------ Hello C语言:什么是程序:程序是指:完成某件事的既定方式和过程.计算机中的程序是指:为了让计算机执 ...
- GO语言学习笔记(一)
GO语言学习笔记 1.数组切片slice:可动态增长的数组 2.错误处理流程关键字:defer panic recover 3.变量的初始化:以下效果一样 `var a int = 10` `var ...
- Go语言学习笔记一: Hello World
Go语言学习笔记一: Hello World 听说Go语言又快又简单.即具有C语言的运行速度,又具有Python语言的开发效率,不知道真的假的.所以特意来学学这门"老"语言. 下载 ...
- 《C# 语言学习笔记》——C# 简介
1 什么是.NET Framework .NET Framework 是Microsoft为开发应用程序而创建的一个富有革命性的新平台. 1.1 .NET Framework 的内容 .NET Fra ...
- Go语言学习笔记(1)——顺序编程
Go语言学习笔记这一堆主要是<Go语言编程>(人民邮电出版社)的读书笔记.中间会穿插一些零碎的点,比如源码学习之类的.大概就是这样吧. 1. 顺序编程 1.1 变量 变量的声明: var ...
- (转)redis 学习笔记(1)-编译、启动、停止
redis 学习笔记(1)-编译.启动.停止 一.下载.编译 redis是以源码方式发行的,先下载源码,然后在linux下编译 1.1 http://www.redis.io/download 先 ...
- Haskell语言学习笔记(88)语言扩展(1)
ExistentialQuantification {-# LANGUAGE ExistentialQuantification #-} 存在类型专用的语言扩展 Haskell语言学习笔记(73)Ex ...
随机推荐
- == equals hashCode 总结比较
在Java中: ==是运算符,用于比较两个变量是否相等. equals,是Objec类的方法,用于比较两个对象是否相等,默认Object类的equals方法是比较两个对象的地址,跟==的结果一样.Ob ...
- 关于Unity中混合模式、Alpha测试、深度测试、通道遮罩、面剔除的使用----渲染通道通用指令(二)
混合模式 着色完成后,需要把颜色混合到帧缓冲区里面,涉及到源和目标. 1:在所有计算完成后,决定当前的计算结果输出到帧缓冲区时,如何混合源和目标,通常用来绘制半透明的物体;2: Blend Off 关 ...
- 关于Unity中顶点片元Shader实例
补充 float4 fixed4 _Time 1: float4是内置向量 (x, y, z, w); float4 a; 访问单独成员a.x, a.y, a.z, a.w;2: fixed4 是内置 ...
- Numpy 的ndarray
创建ndarray 使用array函数 创建一维数组 创建二维数组 并查看有几个列表,每个列表有几个值 查看类型 生成全是0的或者全是1的 具体方法作用
- Linux编程_Shell脚本练习题
1,编写shell脚本,计算1~100的和. #! /bin/bash `;do sum=$[$i+$sum] done echo $sum 2,编写shell脚本,输入一个数字n并计算1~n的和. ...
- C语言中的运算和运算符
一.运算符的优先级和结合性 1,优先级 运算符一览表中,运算符越靠上,优先级越高. 2,结合性 假如用O表示需要两个操作数的双目运算符,那么对于表达式aObOc: 左结合运算符会将表达式解释为 (a ...
- e786. 创建JSpinner组件
This example demonstrates how to build three kinds of spinners. A number spinner: // Create a number ...
- Oracle两个数据库互相访问,DBLink使用-转
测试条件:假设某公司总部在北京,新疆有其下属的一个分公司.在本次测试中,新疆的计算机为本地计算机,即本要的IP地址为:192.168.1.100 北京的总部有一个集中的数据库,其SID是SIDBJ,用 ...
- Python操作SQLServer示例(转)
转自:http://www.cnblogs.com/lrzy/p/4346781.html 本文主要是Python操作SQLServer示例,包括执行查询及更新操作(写入中文). 需要注意的是:读取数 ...
- Java调试那点事[转]
转自云栖社区:https://yq.aliyun.com/articles/56?spm=5176.100239.blogcont59193.11.jOh3ZG# 摘要: 该文章来自于阿里巴巴技术协会 ...