当前位置: 首页 > news >正文

编译和宏的理解

程序的翻译环境和执行环境:
  • 翻译环境,在该环境下源代码被转换为可执行的机器指令。
  • 执行环境,在该环境下用于实际执行的代码。
翻译环境:

编译过程

  • 组成一个程序的每个源文件通过编译过程分别转换成目标代码。
  • 每一个目标文件由链接器链接在一起,形成一个单一而完整的可执行程序。
  • 链接器同时也会引入标准c函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人程序库,将其需要的函数也链接到程序中。
编译的几个阶段的功能:

预处理阶段: 头文件的展开、宏替换、条件编译、去掉注释。
编译阶段: 语法检查、生成汇编代码。
汇编阶段: 形成符号表、将编译阶段生成的汇编代码转换成二进制机器码。
链接阶段: 合并段表、符号表的合并和符号表的重定位,形成一个可执行程序。

运行环境

程序执行的过程:

  1. 程序必须装入内存当中。再有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
  2. 程序的执行便开始。接着便调用main函数。
  3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。
#define
  • #define 定义标识符
#define name stuff

举一些例子:

#define  MAX  1000 //定义一个常数宏
#define  reg  register //为register这个关键字,创建一个简短的名字
#define  do_forever for(;;) //用更形象的符号来替换一种实现
#define  CASE break; case //在写case语句的时候自动把break写上

有个问题?
能不能在#define定义标识符的时候,要不要在最后加上‘;’?

#define MAX 1000;
#define MAX 1000

例:

if(condition)
max=MAX;//替换为max=1000;; 。多了一个;就会出现问题。
else
max=0
  • #define 定义宏
    宏的申明方式:
#define name(parament-list)stuff
//其中的·parament-list是一个由逗号隔开的符号表,它们可能出现在stuff

注意: 参数列表的左括号必须与name紧邻。如果两者之间由任何空白存在,参数列表就会被解释为stuff的一部分。
例子:

#define SQUARE(x) x * x

SQUARE(5;//替换为 5 * 5

int a = 5;
printf("%d",SQUARE(a+1));
//替换为printf("%d",a+1*a+1); 出现了优先级问题

#define SQUARE(x) (x)*(x)

int a = 5;
printf("%d",SQUARE(a+1));
//转换为printf("%d",(a+1) * (a+1)); 解决了函数内部的优先级问题

#define DOUBLE(x) (x)+(x)

int a=5;
printf("%d",10*DOUBLE(a));
//替换为printf("%d",10*5+5);//还是优先级的问题

#define DOUBLE ((a)+(a))//最佳答案

注意:
所有用于对数值表达式进行求值的宏都应该用上面这种方式加上括号,避免在使用宏时由于参数中的操作符或邻近的操作符之间不可预料的相互作用(基本上就是优先级的问题)。

  • #define替换 在程序中拓展#define定义符号时的步骤如下:
    1 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是首先替换.
    2替换文本随后被插入到程序原来文本位置。对于宏,参数名被她们的值替换。
    注意:
    1 宏参数和#define定义可以出现其他#define定义变量。但对于宏,不能出现递归。
    2 当预处理器搜索#define定义符号的时候,字符串常量的内容并不被搜索。

#和##的作用:
#: 把一个宏参数变成对应字符串。
例子:

int i=10;
#define PRINT(FORMAT,VALUE)\
printf("the value of" #VALUE "is "FORMAT " \n",VALUE);
int main()
{i+3
   PRINT("%d",i+3);
   //替换为printf("the value of" i+3 "is "%d " \n",VALUE);
}

#: 可以把位于它两边的符号合成一个符号。它允许宏定义从分离的文本片段创建标识符

#define ADD_TO_SUM(num,value)

int main()
{
ADD_TO_SUM(5,10);
//替换为sum5+=10;
}

宏和函数:
宏和函数的优缺点:
优点:

  1. 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜一筹
  2. 更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以用于>来比较的类型。宏是类型无关的

缺点:

  1. 每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。
  2. 宏是无法调用的。
  3. 宏由于类型无关,所以也就不够严谨。
  4. 可能带来运算符优先级问题,容易出错。

宏有时候可以做到函数做不到的事情。比如参数可以出下类型,而函数不行。

#define MALLO(num,type)\
(type*)malloc(num*sizeof(type))
...
MALLOC(10int);
//替换为(int*)malloc(10*sizeof(int));

相关文章:

  • 时间空间复杂度——详解
  • 【数据结构:队列】——队列的实现(C语言)
  • 【数据结构:栈】——栈的实现(C语言)
  • 【数据结构:链表】——无头单向非循环链表的实现(C语言)
  • 【数据结构:链表】——带头双向循环链表的实现(C语言)
  • 【数据结构:堆】——堆及堆的相关操作(C语言)
  • c++入门——基础知识点(1)
  • c/c++内存管理
  • 函数模板、类模板初识
  • 【Linux】进程地址空间了解
  • 【Linux】入门基础命令(1)
  • c++入门——基础知识点(2)
  • 【Linux】基础文件的I/O操作(1)
  • 【Linux】进程信号
  • 【Linux】网络编程套接字(1)
  • Angular 响应式表单之下拉框
  • Apache的基本使用
  • canvas 高仿 Apple Watch 表盘
  • Dubbo 整合 Pinpoint 做分布式服务请求跟踪
  • JavaScript设计模式系列一:工厂模式
  • Just for fun——迅速写完快速排序
  • magento2项目上线注意事项
  • Making An Indicator With Pure CSS
  • Mysql数据库的条件查询语句
  • python学习笔记 - ThreadLocal
  • 阿里云应用高可用服务公测发布
  • 从零开始的无人驾驶 1
  • 浮动相关
  • 每天10道Java面试题,跟我走,offer有!
  • 深入浅出webpack学习(1)--核心概念
  • 手写一个CommonJS打包工具(一)
  • 算法-插入排序
  • 问题之ssh中Host key verification failed的解决
  • 项目管理碎碎念系列之一:干系人管理
  • 用 Swift 编写面向协议的视图
  • 阿里云服务器如何修改远程端口?
  • 回归生活:清理微信公众号
  • ​比特币大跌的 2 个原因
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • # 安徽锐锋科技IDMS系统简介
  • (4) PIVOT 和 UPIVOT 的使用
  • (二)pulsar安装在独立的docker中,python测试
  • (顺序)容器的好伴侣 --- 容器适配器
  • (转)从零实现3D图像引擎:(8)参数化直线与3D平面函数库
  • (转载)跟我一起学习VIM - The Life Changing Editor
  • .NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划
  • .Net Framework 4.x 程序到底运行在哪个 CLR 版本之上
  • .net mvc 获取url中controller和action
  • .Net Redis的秒杀Dome和异步执行
  • .net 重复调用webservice_Java RMI 远程调用详解,优劣势说明
  • .NET简谈设计模式之(单件模式)
  • /proc/stat文件详解(翻译)
  • ??eclipse的安装配置问题!??
  • ?php echo ?,?php echo Hello world!;?
  • @ResponseBody