专题三:

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语言学习笔记---预编译的更多相关文章

  1. HTML语言学习笔记(会更新)

    # HTML语言学习笔记(会更新) 一个html文件是由一系列的元素和标签组成的. 标签: 1.<html></html> 表示该文件为超文本标记语言(HTML)编写的.成对出 ...

  2. 2017-04-21周C语言学习笔记

    C语言学习笔记:... --------------------------------- C语言学习笔记:学习程度的高低取决于.自学能力的高低.有的时候生活就是这样的.聪明的人有时候需要.用笨的方法 ...

  3. 2017-05-4-C语言学习笔记

    C语言学习笔记... ------------------------------------ Hello C语言:什么是程序:程序是指:完成某件事的既定方式和过程.计算机中的程序是指:为了让计算机执 ...

  4. GO语言学习笔记(一)

    GO语言学习笔记 1.数组切片slice:可动态增长的数组 2.错误处理流程关键字:defer panic recover 3.变量的初始化:以下效果一样 `var a int = 10` `var ...

  5. Go语言学习笔记一: Hello World

    Go语言学习笔记一: Hello World 听说Go语言又快又简单.即具有C语言的运行速度,又具有Python语言的开发效率,不知道真的假的.所以特意来学学这门"老"语言. 下载 ...

  6. 《C# 语言学习笔记》——C# 简介

    1 什么是.NET Framework .NET Framework 是Microsoft为开发应用程序而创建的一个富有革命性的新平台. 1.1 .NET Framework 的内容 .NET Fra ...

  7. Go语言学习笔记(1)——顺序编程

    Go语言学习笔记这一堆主要是<Go语言编程>(人民邮电出版社)的读书笔记.中间会穿插一些零碎的点,比如源码学习之类的.大概就是这样吧. 1. 顺序编程 1.1 变量 变量的声明: var ...

  8. (转)redis 学习笔记(1)-编译、启动、停止

    redis 学习笔记(1)-编译.启动.停止   一.下载.编译 redis是以源码方式发行的,先下载源码,然后在linux下编译 1.1 http://www.redis.io/download 先 ...

  9. Haskell语言学习笔记(88)语言扩展(1)

    ExistentialQuantification {-# LANGUAGE ExistentialQuantification #-} 存在类型专用的语言扩展 Haskell语言学习笔记(73)Ex ...

随机推荐

  1. Linux之计划任务

    计划任务特性 1. 需要在指定的某时间段运行 2. 需要将任务结果邮件通知用户 3. 单次任务及循环任务区别 Linux计划任务的实现工具 1. at工具 其只能执行一次性任务 其会自动加载部分环境变 ...

  2. 【转】【Nginx】Nginx 入门教程 + 常用配置解析

    == Nginx介绍和安装 == Nginx是一个自由.开源.高性能及轻量级的HTTP服务器及反转代理服务器, 其性能与IMAP/POP3代理服务器相当.Nginx以其高性能.稳定.功能丰富.配置简单 ...

  3. Lucene系列四:Lucene提供的分词器、IKAnalyze中文分词器集成、扩展 IKAnalyzer的停用词和新词

    一.Lucene提供的分词器StandardAnalyzer和SmartChineseAnalyzer 1.新建一个测试Lucene提供的分词器的maven项目LuceneAnalyzer 2. 在p ...

  4. 使用jenkins配置.net mvc网站进行持续集成

    最近好久没有更新文章了,因为好久没有写代码了,以至于我不知道同大家分享些什么,刚好,今天突然叫我学习下jenkins每日构建,我就把今天的学习笔记记录下来,这其中很多东西都是公司同事之前调研总结的,我 ...

  5. Windows版Jenkins+SVN+Maven自动化部署环境搭建【转】

    前言 因今年公司新产品线较多,为了降低耦合,达到业务分离.重用,提高内部开发效率的目的,采用了基于服务组件.前后端分离的架构体系.与之前传统单应用架构相比,系统部署.配置更加复杂,为了能够频繁地将软件 ...

  6. Maven最佳实践-distributionManagement

    分发构件至远程仓库 mvn install 会将项目生成的构件安装到本地Maven仓库,mvn deploy 用来将项目生成的构件分发到远程Maven仓库.本地Maven仓库的构件只能供当前用户使用, ...

  7. spring mvc实现自定义注解

    实现方式:使用@Aspect实现: 1. 新建注解接口:CheckSign package com.soeasy.web.utils; import org.springframework.core. ...

  8. 机器学习——利用PCA来简化数据

    降维技术的好处: 1.使得数据集更易使用 2.降低很多算法的计算开销 3.取出噪声 4.使得结果易懂 在已标注和未标注的数据上都有降维技术,降维的方法: 1.主成分分析(Principal Compo ...

  9. Web4个实验题目DOM+JS

    实验目的: 1. 掌握DOM对象的基本语法 2. 掌握getElementById函数 3. 掌握getElementsByTagName函数 来源http://www.cnblogs.com/xia ...

  10. [Learn AF3]第四章 App framework组件之Button

    Button    组件名称:Button     是否js控件:否     使用说明:如果说panel组件是af3的“核心(heart of the ui)”,那么Button就是af中的五虎上将之 ...