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

C语言--编译和链接

1.翻译环境

计算机能够执行二进制指令,我们的电脑不会直接执行C语言代码,编译器把代码转换成二进制的指令;

我们在VS上面写下printf("hello world");这行代码的时候,经过翻译环境,生成可执行的exe文件,这个主要是编译器完成,生成可执行的文件以后,要进行运行,这个运行主要是由我们的操作系统决定的;

windows环境下面,.c文件经过编译器(cl.exe)的处理,生成.obj的目标文件,这个里面可能会有多个源文件,每个源文件都会生成各自的目标文件,这个过程就叫做编译;目标文件和链接库经过链接器(link.exe)的处理就生成了可执行文件,这个过程叫做链接;

2.预处理(简介)

编译其实是分3个过程的,分别是预处理生成.i文件,编译生成.s文件,汇编生成.o文件;

预处理的时候会展开头文件,处理编译指令,删掉我们写的注释(通过这个地方我们也可以看出来注释是写给我们程序员自己看的,并不会真正的到目标文件里面),预处理主要是处理那些以#开头的指令;

3.编译

词法分析,语法分析,语义分析,主要是把C代码(我们可以读懂)转换成为汇编代码(我们无法读懂);

词法分析:将源代码程序被通过扫描器简单的进⾏词法分析,把代码中的字符分割成⼀系列 的记号(关键字、标识符、字⾯量、特殊字符等);

语法分析是以表达式为节点生成语法树;

语义分析主要是进行数据类型的区分,以及数据类型的匹配;

汇编是把汇编代码转换成为机器指令,机器指令就是我们常说的二进制指令;

4.链接

解决一个项目里面多文件,多模块之间可以相互调用,进行地址和空间分配;把多个目标文件进行合并;这个时候我们就是合并相同的函数的地址(会取函数的有效地址),地址修订的过程就叫做重定位,这样不同的函数之间就可以相互调用;

5.预处理(详细)

(1)预处理符号

int main()
{printf("%s\n", __FILE__);printf("%s\n", __DATE__);printf("%s\n", __TIME__);printf("%d\n", __LINE__);return 0;
}

这些符号就是已经存在的,我们可以直接进行使用,第一个是打印文件的名字,第二个是创建的日期,第三个打印创建的日期,第四个是行号;这个日期和时间是文件被编译的瞬间的时间和日期

(2)#define

#define可以定义符号常量,这个符号在代码里面出现的时候都会被替换为对应的内容;

#include<stdio.h>
#define MAX 1000
#define ASD "hello world"
int main()
{printf("%d\n", MAX);printf("%s\n", ASD);return 0;
}

对于#define定义符号的时候,我们不需要在结尾加上分号,这个时候加上分号就是多余的;

由此可见,如果加上分号,会让编译器默认为你的定义是后面带上分号的1000,这个问题很常见,例如下面的判断语句;

这个简单的if.....else语句报错的原因就是我们加了分号,因为在默认的情况下,如果没有中括号,if只会执行一条语句,但是这个地方MAX自带分号,结尾又有一个分号,相当于是2个语句,所以轮到else执行的时候就会报错;

#define也可以定义宏,下面就是一个具体的案例:

宏的定义类似于函数,但是括号里面没有参数,预处理以后就变成了int ret=a*a;就相当于把a带入define里面的x,把宏体替换回主函数里面的ret语句,下面我们使用表达式进行代换,看看结果:

可能在我们的直觉里面,a+1=6,6*6=36,但是最后打印输出的结果确是11,为什么会这样呢,实际上他在替换的时候,是这样进行替换的,a+1*a+1,我们计算的时候会把a+1看作一个整体,但是预处理不会,他会先计算乘法1*a=5,5+5+1=11,打印输出结果;如果我们想要得到正确结果,我们可以加上中括号就可以了:

因此用于对数值表达式进行求值的宏定义的时候,我们应该带上括号;否则参数会和就近的运算符结合进行运算,可能无法达到我们想要的结果;

(3)带有副作用的宏

什么叫做副作用呢,我们通过一个简单的例子理解一下:

这个例子里面第一个表达式计算以后a=11,b=10,第二个表达式计算以后a=11,b=11,这个时候我们就可以说,++具有副作用,因为他在赋值的同时,把b的数值也给改变了;

下面我i们学习一下宏的副作用:

这个例子是想要说明使用宏求最大值的时候,这个例子里面替换以后就是:

(a++)>(b++)?(a++):(b++)a++以后先使用后加加,就是带进去的值是3,a的值是4,同理,b++带进去的值是5,b的值是6,但是3>5显然不对,因此执行后半句,也就是b++,这个时候b本来就是6了,加加就会变成7,由此可见,这个过程加加执行了2次,可能并不是我们想要的结果,而且具有不确定性,如果是前面的大,就会是a++执行2次,我们称这种现象叫做宏的副作用;

(4)宏和函数

宏和函数其实是各有利弊的,概括起来,我们可以这样讲,通过前面的一些案例,我们也发现了宏和函数貌似具有一些相似的功能,我们在处理一些比较简单的问题的时候,我们可以使用宏,因为相比较于函数,宏的执行速度和效率会比函数高,因为函数就会涉及到函数的调用以及函数的返回,这些过程我们使用宏都不会遇到,因此使用宏可以节省时间,但是宏自身也是有弊端的,因为宏对于参数的要求不像函数那样严格,因此我们使用的时候可能会出现问题,而且像我们前面提到的,宏的使用可能会出现我们难以预料的副作用,还涉及运算符号的优先级的结合问题;但是函数会在类型完全匹配的时候才回去进行调用,这个方面函数更加保险;

(5)命名规则

这个是我们一般遵守的规则,这个可以用来区分一般的函数和宏的定义,宏在定义的时候一般都是全部大写,但是函数不会全部大写;

(6)条件编译

下面我们认识一些常见的条件编译指令,

#if  #endif指令

int main()
{
#if 0int a = 10;int b = 20;printf("%d", a + b);return 0;
#endif
}

这个地方因为在#if的后面是0,所以在条件编译里面的代码就不会被执行了,

#define xxxx
#if xxxxx
**********
#endif
这个条件编译指令可以达到相同的效果;
#define MAX 0
int main()
{
#if MAXint a = 10;int b = 20;printf("%d", a + b);return 0;
#endif
}

(7)头文件的包含

我们使用的包含自己的文件就是使用双引号,包含库里面的文件就是使用尖括号,这两者的区别就是:使用双引号包含会先从当前的文件路径下面进行寻找,找不到的话再到库里面去寻找,使用尖括号就会直接到库里面去寻找,当然,#include<stdio.h>我们都知道这个是库里面的,但是如果我们使用双引号代替尖括号,也可以运行,因为在当前的目录下面找不到,最后还是会到库里面去找,但是这样就浪费时间,我们一般不会这样做;

我们不同的文件相互包含,可能会出现头文件被多次包含的问题,这样做的话,如果头⽂件⽐较⼤,这样预处理后代码量会剧增;我们在头⽂件中添加 ifndef/define/endif解决被多次包含的问题,当然,我们也是可以在头文件里面添加pragma once这样我们的头文件就只会被包含一次了;

(8)取消宏定义

#define MAX 10
int main()
{int a = 10;int b = 20;
#undef MAXfor (int i = 0; i < MAX; i++)//这里会报错{a++;b++;}printf("%d", a + b);return 0;
}

我们在开头定义MAX宏,我们可以使用#undef指令取消宏的定义,取消之后,如果我们继续使用的话,就会报错了;

(9)#和##

我们在认识这两个符号之前,我们先铺垫一些只是,这个会在#和##的代码里面使用到

int main()
{printf("what are you doing""\n");printf("what are ""you doing""\n");return 0;
}

打印结果:

这个铺垫就是这两种写法的效果是一样的,也就是说如果都是字符串,系统会自动的进行合并字符串的操作;接下来我们了解了这一点再来学习这两种符号的用法:

我们首先对比一下使用#和不使用的区别;

不使用:

使用#的打印结果:

因此,我们可以概括:#运算符所执⾏的操作可以理解为”字符串化“。

##的用法:把位于它两边的符号合成⼀个符号,它允许宏定义从分离的⽂本⽚段创建标识符。 ## 被称 为记号粘合;

写⼀个函数求2个数的较⼤值的时候,不同的数据类型就得写不同的函数。

int int_max(int x, int y)
{return x>y?x:y;
}
float float_max(float x, float y)
{return x>yx:y;
}
但是这样写起来太繁琐了,现在我们这样写代码试试:
//宏定义
#define GENERIC_MAX(type) \
type type##_max(type x, type y)\
{ \return (x>y?x:y); \
}

注释:这里的\是续行符;

GENERIC_MAX(int) //替换到宏体内后int##_max ⽣成了新的符号 int_max做函数名
GENERIC_MAX(float) //替换到宏体内后float##_max ⽣成了新的符号 float_max做函数名
int main()
{//调⽤函数int m = int_max(2, 3);printf("%d\n", m);float fm = float_max(3.5f, 4.5f);printf("%f\n", fm);return 0;
}

这样利用##符号,我们同样可以实现不同类型数据的比较的目的。

相关文章:

C语言--编译和链接

1.翻译环境 计算机能够执行二进制指令&#xff0c;我们的电脑不会直接执行C语言代码&#xff0c;编译器把代码转换成二进制的指令&#xff1b; 我们在VS上面写下printf("hello world");这行代码的时候&#xff0c;经过翻译环境&#xff0c;生成可执行的exe文件&…...

实现使用C#代码完成wifi的切换和连接功能

实现使用C#代码完成wifi的切换和连接功能 代码如下&#xff1a; namespace Wifi连接器 {public partial class Form1 : Form{private List<Wlan.WlanAvailableNetwork> NetWorkList new List<Wlan.WlanAvailableNetwork>();private WlanClient.WlanInterface Wla…...

Mac添加和关闭开机应用

文章目录 mac添加和关闭开机应用添加开机应用删除/查看 mac添加和关闭开机应用 添加开机应用 删除/查看 打开&#xff1a;系统设置–》通用–》登录项–》查看登录时打开列表 选中打开项目&#xff0c;点击“-”符号...

QT QInputDialog弹出消息框用法

使用QInputDialog类的静态方法来弹出对话框获取用户输入&#xff0c;缺点是不能自定义按钮的文字&#xff0c;默认为OK和Cancel&#xff1a; int main(int argc, char *argv[]) {QApplication a(argc, argv);bool isOK;QString text QInputDialog::getText(NULL, "Input …...

Unity3d使用Jenkins自动化打包(Windows)(一)

文章目录 前言一、安装JDK二、安装Jenkins三、Jenkins插件安装和使用基础操作 实战一基础操作 实战二 四、离线安装总结 前言 本篇旨在介绍基础的安装和操作流程&#xff0c;只需完成一次即可。后面的篇章将深入探讨如何利用Jenkins为Unity项目进行打包。 一、安装JDK 1、进入…...

HarmonyOS 应用开发之Want的定义与用途

Want 是一种对象&#xff0c;用于在应用组件之间传递信息。 其中&#xff0c;一种常见的使用场景是作为 startAbility() 方法的参数。例如&#xff0c;当UIAbilityA需要启动UIAbilityB并向UIAbilityB传递一些数据时&#xff0c;可以使用Want作为一个载体&#xff0c;将数据传递…...

enscan自动化主域名信息收集

enscan下载 Releases wgpsec/ENScan_GO (github.com) 能查的分类 实操&#xff1a; 首先打开linux 的虚拟机、 然后把下面这个粘贴到虚拟机中 解压后打开命令行 初始化 ./enscan-0.0.16-linux-amd64 -v 命令参数如下 oppo信息收集 运行下面代码时 先去配置文件把coo…...

分享全栈开发医疗小程序 -带源码课件(课件无解压密码),自行速度保存

课程介绍 分享全栈开发医疗小程序 -带源码课件&#xff08;课件无解压密码&#xff09;&#xff0c;自行速度保存&#xff01;看到好多坛友都在求SpringBoot2.X Vue UniAPP&#xff0c;全栈开发医疗小程序 - 带源码课件&#xff0c;我看了一下&#xff0c;要么链接过期&…...

基于YOLOv8与ByteTrack实现多目标跟踪——算法原理与代码实践

概述 在目标检测中&#xff0c;有许多经算法如Faster RCNN、SSD和YOLO的各种版本&#xff0c;这些算法利用深度学习技术&#xff0c;特别是卷积神经网络&#xff08;CNN&#xff09;&#xff0c;能够高效地在图像中定位和识别不同类别的目标。Faster RCNN是一种基于区域提议的…...

C语言——函数练习程序

1.从终端接收一个数,封装一个函数判断该数是否为素数 #include <stdio.h>int pri(int num) {int i 0;for (i 2; i < num; i){if (num % i 0){return 0;break;}}if (i num-1){return 1;} }int main(void) {int num 0;int ret 0;scanf("%d", &num);…...

ssh 启动 docker 中 app, docker logs 无日志

ssh 启动 app, 标准输出被重定向 ssh 客户端&#xff0c;而不是 docker 容器的标准输出。只需要在启动时把app 标准输出重定向到 docker标准输出。 测试如下&#xff1a; 1.启动 docker docker run -it -p 60022:22 --name test test:v4 bash -c "service ssh restart;…...

WPF---1.入门学习

&#x1f388;个人主页&#xff1a;靓仔很忙i &#x1f4bb;B 站主页&#xff1a;&#x1f449;B站&#x1f448; &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;WPF &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xf…...

Vue3 + Vite + TS + Element-Plus + Pinia项目(5)对axios进行封装

1、在src文件夹下新建config文件夹后&#xff0c;新建baseURL.ts文件&#xff0c;用来配置http主链接 2、在src文件夹下新建http文件夹后&#xff0c;新建request.ts文件&#xff0c;内容如下 import axios from "axios" import { ElMessage } from element-plus im…...

【Rust】——编写自动化测试(一)

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…...

第十二章 微服务核心(一)

一、Spring Boot 1.1 SpringBoot 构建方式 1.1.1 通过官网自动生成 进入官网&#xff1a;https://spring.io/&#xff0c;点击 Projects --> Spring Framework&#xff1b; 拖动滚动条到中间位置&#xff0c;点击 Spring Initializr 或者直接通过 https://start.spring…...

MySQL索引18连问,谁能顶住

前言 过完这个节&#xff0c;就要进入金银季&#xff0c;准备了 18 道 MySQL 索引题&#xff0c;一定用得上。 作者&#xff1a;感谢每一个支持&#xff1a; github 1. 索引是什么 索引是一种数据结构&#xff0c;用来帮助提升查询和检索数据速度。可以理解为一本书的目录&…...

[flink 实时流基础系列]揭开flink的什么面纱基础一

Apache Flink 是一个框架和分布式处理引擎&#xff0c;用于在无边界和有边界数据流上进行有状态的计算。Flink 能在所有常见集群环境中运行&#xff0c;并能以内存速度和任意规模进行计算。 文章目录 0. 处理无界和有界数据无界流有界流 1. Flink程序和数据流图2. 为什么一定要…...

开放平台 - 互动玩法演进之路

本期作者 1. 背景 随着直播业务和用户规模日益壮大&#xff0c;如何丰富直播间内容、增强直播间内用户互动效果&#xff0c;提升营收数据变得更加关键。为此&#xff0c;直播互动玩法应运而生。通过弹幕、礼物、点赞、大航海等方式&#xff0c;用户可以参与主播的直播内容。B站…...

Linux之进程控制进程终止进程等待进程的程序替换替换函数实现简易shell

文章目录 一、进程创建1.1 fork的使用 二、进程终止2.1 终止是在做什么&#xff1f;2.2 终止的3种情况&&退出码的理解2.3 进程常见退出方法 三、进程等待3.1 为什么要进行进程等待&#xff1f;3.2 取子进程退出信息status3.3 宏WIFEXITED和WEXITSTATUS&#xff08;获取…...

RegSeg 学习笔记(待完善)

论文阅读 解决的问题 引用别的论文的内容 可以用 controlf 寻找想要的内容 PPM 空间金字塔池化改进 SPP / SPPF / SimSPPF / ASPP / RFB / SPPCSPC / SPPFCSPC / SPPELAN &#xfffc; ASPP STDC&#xff1a;short-term dense concatenate module 和 DDRNet SE-ResNeXt …...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

谷歌浏览器插件

项目中有时候会用到插件 sync-cookie-extension1.0.0&#xff1a;开发环境同步测试 cookie 至 localhost&#xff0c;便于本地请求服务携带 cookie 参考地址&#xff1a;https://juejin.cn/post/7139354571712757767 里面有源码下载下来&#xff0c;加在到扩展即可使用FeHelp…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句&#xff0c;它能够让用户直接在浏览器内练习SQL的语法&#xff0c;不需要安装任何软件。 链接如下&#xff1a; sqliteviz 注意&#xff1a; 在转写SQL语法时&#xff0c;关键字之间有一个特定的顺序&#xff0c;这个顺序会影响到…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...