【C语言】文件的编译链接和预处理

文件的编译链接和预处理

  • 程序的翻译环境和执行环境
    • 翻译环境
      • 预处理(预编译)过程
      • 编译过程
      • 汇编过程
      • 链接过程
    • 运行环境
  • 预处理详解
    • 预处理符号
    • 预处理指令
    • #define
      • #define定义标识符
      • #define定义宏
      • #define替换规则
    • #与##
      • #的使用
      • ##的使用
    • 带有副作用的宏参数
    • 宏与函数的对比
      • 宏的优势
      • 函数的优势
      • 宏与函数的命名约定
    • undef
    • 命令行定义
    • 条件编译

程序的翻译环境和执行环境

在ANSIC的任何一种实现中,存在俩个不同的环境:
1.翻译环境,在这个环境中源代码被转换为可执行的机器指令(二进制指令)
2.执行环境,用于执行代码

  • 计算机只能执行二进制的指令

翻译环境

在这里插入图片描述

在这里插入图片描述

在程序编译过程:

  • 组成一个程序的每一个源文件通过编译过程分别转换为目标代码
  • 每个目标文件有链接器捆绑在一起,形成一个单一而完整的可执行程序
  • 链接器同时也会引入标准C函数中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将器所需要的函数也链接到其中
  • 每一个源文件会单独被编译器处理为目标文件

预处理(预编译)过程

1.#include头文件的包含
2.#define定义符号的替换和删除
3.注释的删除

  • 预处理(预编译)过程属于文本操作过程

编译过程

将C语言代码翻译成汇编代码

  • 语法分析
  • 词法分析
  • 语义分析
  • 符号分析

汇编过程

1.将汇编代码翻译成二进制指令(存放目标文件)
2.形成符号表

链接过程

1.合并段表
2.符号表的合并和符号表的重定义

【注意】把gcc移植到windows环境,编译产生的程序想在windows上运行,就得按照windows的可执行程序的格式进行

运行环境

在程序执行的过程:

1.程序必须载入内存中,在有操作系统的环境中:一般由操作系统完成,在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存完成

2.程序的执行便开始。接着便调用main函数

3.开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。

4.终止程序。正常终止main函数;也有可能是意外终止。

预处理详解

预处理符号

在这里插入图片描述

int main(void)
{printf("%s\n",__FILE__);printf("%s\n",__LINE__);printf("%s\n",__DATE__);printf("%s\n",__TIME__);printf("%s\n",__STDC__);printf("%s\n",__FUNCTION__);return 0;
}
  • 这些预定义符号都是语言内置

预处理指令

1.#define
2.#include
3.#pragma
4.#error
5.#line

#define

#define定义标识符

#define name staff

  • define 定义一个数字
#define MAX 100
#define min 5
  • define 创建一个新名字
#define reg register
  • define 使用另外一个符号替换实现
#define do_forever for(;;)

注意:一般使用define定义标识符时,不使用;

#define定义宏

#define机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏或者定义宏

  • 宏的声明方式:
    #define name(parament-list) stuff
    其中的parament-list是一个由逗号隔开的符号表,可能出现在stuff中。

【注意】参数列表的左括号必须与name紧邻,如果俩种之间由任何空白存在,参数列表就会被解释为stuff的一部分

  • 宏可以看作是一种替换
#define ADD(x,y) x+yint main(void)
{int a = 10;int b = 20;printf("%d",ADD(a,b));return 0;
}

【注意】所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用。

#define替换规则

在程序中扩展#define定义符号和宏时,需要涉及几个步骤。

  1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。
  2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值替换。
  3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。

注意:

  1. 宏参数和#define 定义中可以出现其他#define定义的变量。但是对于宏,不能出现递归。
  2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。

#与##

#的使用

将宏的参数变成对应的字符串

#define PRINTF(format,value)  printf("the value of "#value"is"format"\n",value)int main(void)
{int i = 10;PRINT("%d",i);return 0;
}

##的使用

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

#define F(x,y) x##E##y
#include<stdio.h>
int main(void)
{printf("%f",F(2,-5));return 0;
}

带有副作用的宏参数

#define ADD(x,y) x+y
int main(void)
{int b = ++a;printf("%d",ADD(b,b));return 0;
}

当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。

宏与函数的对比

宏的优势

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

函数的优势

  1. 每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。
  2. 宏是没法调试的
  3. 宏由于类型无关,也就不够严谨
  4. 宏可能会带来运算符优先级的问题,导致程序出错
属 性#define定义宏函数
代码长度每次使用时,宏代码都会被插入到程序中。除了非常小的宏之外,程序的长度会大幅度增长函数代码只出现于一个地方;每次使用这个函数时,都调用那个地方的同一份代码
执行速度更快存在函数的调用和返回的额外开销, 所以相对慢一些
操作符优先级宏参数的求值是在所有周围表达式的上下文环境里,除非加上括号,否则邻近操作符的优先级可能会产生不可预料的后果,所以建议宏在书写的时候多些括号函数参数只在函数调用的时候求值一次,它的结果值传递给函数。表达式的求值结果更容易预测。
带有副作用的参数参数可能被替换到宏体中的多个位置,所以带有副作用的参数求值可能会产生不可预料的结果。函数参数只在传参的时候求值一次,结果更容易控制。
参数类型宏的参数与类型无关,只要对参数的操作是合法的,它就可以使用于任何参数类型。函数的参数是与类型有关的,如果参数的类型不同,就需要不同的函数,即使他们执行的任务是不同的
调试宏是不方便调试的函数是可以逐语句调试的
递归宏是不能递归的函数是可以递归的

宏与函数的命名约定

  • 宏的名字全部大写
  • 函数名的每个英文单词首字母大写

undef

#undef用于移除一个宏定义

#define ADD(x,y) x+y
#undef ADD

命令行定义

在命令行中定义符号。用于启动编译过程。

条件编译

在编译一个程序的时候如果一条语句(一组语句)编译或者放弃是很方便的

  • 这种情况适合于:调试型代码,删除可惜,保留多余
#if 常量表达式//... 
#endif 
//常量表达式由预处理器求值。

2.多个分支的条件编译

#if 常量表达式//... 
#elif 常量表达式//... 
#else //... 
#endif 

3.判断是否被定义

#if defined(symbol) 
#ifdef symbol #if !defined(symbol) 
#ifndef symbol 

4.嵌套指令

#if defined(OS_UNIX) #ifdef OPTION1 unix_version_option1(); #endif #ifdef OPTION2 unix_version_option2(); #endif #elif defined(OS_MSDOS) #ifdef OPTION2 msdos_version_option2(); #endif 
#endif 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/840252.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

超详细的前后端实战项目(Spring系列加上vue3)前端篇(二)(一步步实现+源码)

好了&#xff0c;兄弟们&#xff0c;继昨天的项目之后&#xff0c;开始继续敲前端代码&#xff0c;完成前端部分 昨天完成了全局页面的代码&#xff0c;和登录页面的代码&#xff0c;不过昨天的代码还有一些需要补充的&#xff0c;这里添加一下 内容补充&#xff1a;在调用登…

代码随想录算法训练营第36期DAY38

DAY38 435无重叠区间 昨晚很快就想出来了&#xff0c;今天相当于二刷。 class Solution {public: static bool mycmp(vector<int>&a,vector<int>&b){ return a[1]<b[1]; } int eraseOverlapIntervals(vector<vector<int>&g…

如何部署一个基本符合ERC20的智能合约

运行genache-cli 运行以下命令genache-cli下载MetaMask浏览器拓展钱包 添加账户 导入账户 输入genache-cli生成其中的密钥 选择【显示测试网络】点击【添加网络】 添加自己本地的网络 选择该测试网络&#xff0c;账号里就会有100RETH 在remix里接通这个测试帐号 …

10.2.k8s的附加组件-Metrics-server组件与hpa资源pod水平伸缩

目录 一、概述 二、安装部署Metrics-Server组件 1.下载Metrics-Server资源清单 2.编辑Metrics-Server的资源清单 3.验证Metrics-Server是否成功安装 4.使用top命令测试是否管用 三、hpa资源实现pod水平伸缩&#xff08;自动扩缩容&#xff09; 1.编写deploy资源清单 2.…

Sap Hana 数据迁移同步优化(二)

简述 CloudCanal 近期对 Hana 源端链路做了新一轮优化&#xff0c;这篇文章简要做下分享。 本轮优化主要包含: 表级别 CDC 表表级别任务位点表级别触发器 单 CDC 表的问题 CloudCanal 在实现 Hana 源端增量同步时&#xff0c;最初采用的是单 CDC 表的模式。 即所有订阅表…

【C语言】深入理解指针(一)(上)

本篇文章将讲解&#xff1a; &#xff08;1&#xff09;内存和地址 &#xff08;2&#xff09;指针变量和细致 &#xff08;3&#xff09;指针变量类型的意义 一&#xff1a;内存和地址 &#xff08;1&#xff09;内存 在讲内存和地址之前&#xff0c;我们讲一个生活中的…

Three.js 研究:1、如何让物体动起来

1、制作模型动画 2、模型动画在代码中的调用 使用这个例子进行修改&#xff0c;使他能动作webgl_animation_skinning_morph.html 制作好的模型放到如下路径 /three.js-master/examples/models/gltf/无标题.gltf修改加载模型文件的地址 修改动画名称 运行 点击动画后&…

彩虹聚合二级域名DNS管理系统源码v1.3

聚合DNS管理系统可以实现在一个网站内管理多个平台的域名解析&#xff0c; 目前已支持的域名平台有&#xff1a;阿里云、腾讯云、华为云、西部数码、CloudFlare。 本系统支持多用户&#xff0c;每个用户可分配不同的域名解析权限&#xff1b;支持API接口&#xff0c; 支持获…

Oracle 证书的重要性

随着信息技术的飞速发展&#xff0c;数据库管理已成为企业运营中不可或缺的一部分。Oracle作为全球领先的数据库管理系统提供商&#xff0c;其Oracle Certified Professional&#xff08;OCP&#xff09;认证已成为数据库管理员和开发人员追求的专业认证之一。本文将深入探讨Or…

标准化软件实施方案(直接套用即可)

软件实施方案 二、 项目介绍 三、 项目实施 四、 项目实施计划 五、 人员培训 六、 项目验收 七、 售后服务 八、 项目保障措施 软件开发全套资料获取&#xff1a;&#xff08;本文末个人名片也可直接获取&#xff09;软件开发全套资料_数字中台建设指南-CSDN博客 软件产品&am…

接口响应断言

目录 接口断言介绍接口断言方式介绍响应状态码断言 课程目标 掌握什么是接口断言。了解接口断言的多种方式。掌握如何对响应状态码完成断言。 思考 这两段代码是完整的接口自动化测试代码吗&#xff1f; …省略… when().get(“https://httpbin.ceshiren.com/get?namead&…

【LeetCode算法】第58题:最后一个单词的长度

目录 一、题目描述 二、初次解答 三、官方解法 四、总结 一、题目描述 二、初次解答 1. 思路&#xff1a;双指针法。low指向单词头&#xff0c;high指向单词后的空格&#xff0c;则high-low就是每个单词的长度。算法步骤&#xff1a;①low从头往后查找第一个非空格的字符&…

Python 将文件夹中的图片信息导入到 Excel 的表格

引言 在数据处理和管理的日常任务中&#xff0c;经常需要将文件夹中的图片文件信息&#xff08;如文件名、路径、创建日期、大小、分辨率等&#xff09;整理成一个 Excel 表格。这篇博客将介绍如何使用 Python 中的 wxPython 模块创建一个 GUI 应用&#xff0c;用户可以通过这…

【Linux】用户级缓冲区

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和算法 ✈️专栏&#xff1a;Linux &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵&#xff0c;希望大佬指点一二 如果文章对…

微服务项目收获和总结---第4天(文章审核和保存)

文章审核以及APP端保存文章 业务流程&#xff1a; App端保存接口&#xff1a; 数据库表详情 文章的基本信息表&#xff1a;id&#xff0c;标题&#xff0c;作者id&#xff0c;频道id...... 文章的权限/配置表&#xff1a;存储文章是否可以评论&#xff0c;是否上架&#xff…

开源实用!猫抓媒体嗅探浏览器插件

CatCatch&#xff1a;网络资源&#xff0c;一触即发 - 精选真开源&#xff0c;释放新价值。 概览 CatCatch是一个专为浏览器设计的资源嗅探扩展&#xff0c;旨在帮助用户轻松捕获和分析网页中的各种资源。无论是视频、音频还是其他类型的文件&#xff0c;猫爪都能提供直观的界…

在XP/Vista系统下使用Node.js的babel-cli命令行工具转码ES6语法的js文件,让IE8浏览器也能运行

在XP系统下IE浏览器最高只能装到IE8&#xff0c;在Vista系统下最高只能装到IE9。 2015年以后&#xff0c;JavaScript新增了很多语法&#xff0c;比如class、extends&#xff0c;还有let和const等等&#xff0c;这些语法都是XP下的终端浏览器IE8所不支持的。要想让使用了这些新式…

AI爆文写作:关注热点,提前埋伏好关键词,吃系统的热点推荐,吃搜索流量,让你的文章直接爆了!

做内容&#xff0c;要对热点敏感。 小米汽车的发布会时间&#xff0c;我们是不是提前就知道&#xff0c;发布会前&#xff0c;大家最关注的就是价格。 你看这个相关关键词搜索&#xff0c;10W太多了。 我看到有博主在发布会前&#xff0c;埋伏了一篇&#xff0c;公众号也有推…

读人工智能时代与人类未来笔记13_网络57

1. jun背控制 1.1. 威慑的目的是通过威胁发动盒站来防止盒站 1.2. jun背控制的目的是通过限制甚至废除57&#xff08;或57类别&#xff09;本身来防止盒站真 1.2.1. 与盒不扩散相配合&#xff0c;以一整套详尽的条约、技术保障措施、监管和其他控制机制为支撑&#xff0c;所…

B站pink老师CSS学习(二)

文章目录 一、emmet语法1.快速生成HTML结构语法 二、复合选择器1.什么是复合选择器2.后代选择器3.子选择器4.并集选择器5.伪类选择器6.链接伪类选择器7&#xff1a;focus伪类选择器8.总结 三、元素的显示模式1.什么是元素显示模式2.块元素3.行内元素4.行内块元素5.总结6.元素显…