import{_ as s,c as a,o as i,a6 as n}from"./chunks/framework.CZKtKhAm.js";const l="/c/assets/1.D4a42fT1.jpg",e="/c/assets/2.D2wnxl5F.png",p="/c/assets/3.Dq625oo9.jpg",t="/c/assets/4.uqu1DEK4.png",r="/c/assets/5.C6Q0Q8kf.jpg",h="/c/assets/6.B4Srsb-0.png",c="/c/assets/7._D_c8Lrn.png",d="/c/assets/8.DlIyFGDg.png",o="/c/assets/9.7zkUmpQw.png",k="/c/assets/10.h1ugtjyX.png",u="/c/assets/11.D5PWTabw.png",g="/c/assets/12.Bvs6QYjl.jpg",b="/c/assets/9.7zkUmpQw.png",m="/c/assets/14.CsR5exrN.png",E="/c/assets/15.BRG9GQdT.png",C="/c/assets/16.C2sciGZn.png",y="/c/assets/17.DdyXXyxJ.png",F="/c/assets/18.DIeb_KXW.png",_="/c/assets/19.C-kvMz2p.png",v="/c/assets/20.CQqFxmDa.png",B="/c/assets/21.CjMWyIiX.png",A="/c/assets/22.DFQhcDgs.png",f="/c/assets/23.Cco1vsW8.png",x="/c/assets/24.D60Zf6_d.png",D="/c/assets/25.D2-G6nV2.png",q="/c/assets/26.DpzkVk5V.png",S="/c/assets/27.BXk95GIP.png",w="/c/assets/28.CbWTB08W.png",L="/c/assets/29.twO9TCIg.png",P="/c/assets/30.CKOjeIvS.png",T="/c/assets/31.DKmR0CxE.png",U="/c/assets/32.Cudf77_s.gif",I="/c/assets/33.BBUUlhRC.png",W="/c/assets/34.iLABkB7O.png",O="/c/assets/35.BQuYWOU9.png",N="/c/assets/36.CslpH6j0.png",R="/c/assets/37.BAyvZdKq.png",M="/c/assets/38.C3oC1iUd.png",X="/c/assets/39.Ds-jsEZn.png",G="/c/assets/40.Cd37gMYs.png",V="/c/assets/41.CAw2z3gc.png",$="/c/assets/42.DdPThnr-.png",H="/c/assets/43.q_rvlDnY.png",K="/c/assets/44.JRHg9RZA.png",j="/c/assets/45.Baq-Hb06.png",Q="/c/assets/46.c1ht53mu.png",J="/c/assets/47.CAZmH5Py.png",Y="/c/assets/48.DWeCYBe9.png",z="/c/assets/49.2XM8pYni.png",Z="/c/assets/50.CN0t-fuo.png",ss="/c/assets/51.AcDh3LXQ.png",as="/c/assets/52.CUkDFAc6.png",is="/c/assets/53.picNTNaJ.png",ns="/c/assets/54.DKX92RgJ.png",ls="/c/assets/55.Bxr7QKI3.png",es="/c/assets/56.DuFWsOgW.png",ps="/c/assets/57.Da9qUcfr.png",ts="/c/assets/58.7_gEABSX.gif",rs="/c/assets/59.C2KQYoVC.gif",hs="/c/assets/60.RTUP8Vtx.png",cs="/c/assets/61.Dq21DxwL.png",ds="/c/assets/62.QmpUaNxU.png",os="/c/assets/63.DP0C29gZ.png",ks="/c/assets/64.DwzHokd4.png",us="/c/assets/65.Bi6K26yA.png",gs="/c/assets/66.Bw8DcEQ_.png",bs="/c/assets/67.DPc8Z9rS.png",ms="/c/assets/68.S84xHMTl.png",Es="/c/assets/69.iw3JQUkn.png",Cs="/c/assets/70.ILeJt-HK.png",ys="/c/assets/71.CHgm7khh.png",Fs="/c/assets/72.N1nqJaEg.png",_s="/c/assets/73.DHsnibMi.png",vs="/c/assets/74.BQr6Q0uV.png",Bs="/c/assets/75.BVemi2Lh.png",As="/c/assets/76.BHR69UXx.png",fs="/c/assets/77.CPSU5SJI.png",xs="/c/assets/78.CaQLoDlw.png",Ds="/c/assets/79.aRGy4XbL.png",qs="/c/assets/80.kNO9fmPR.png",Ss="/c/assets/81.D4EkoC4o.png",ws="/c/assets/82.V23Lo9e_.png",Ls="/c/assets/83.Du9LVeMB.png",Ps="/c/assets/84.DdFg75U9.png",Ts="/c/assets/85.C6bz6KtT.png",Us="/c/assets/86.CB6LAhB5.png",Is="/c/assets/87.Bip8bkua.png",Ws="/c/assets/88.DRNHRduW.png",Os="/c/assets/89.Cth4qqEn.png",Ns="/c/assets/90.DWGWZ64P.png",Rs="/c/assets/91.3hDIDdvx.png",Ms="/c/assets/92.Bw_dQ4ap.png",Xs="/c/assets/93.Cn_ubTyA.png",Gs="/c/assets/94.C84EBqwB.png",Vs="/c/assets/95.dZfJY4eR.png",$s="/c/assets/96.B0zm0Z79.png",Hs="/c/assets/97.CaTcEy1Q.png",Ks="/c/assets/98.iEc8mo9g.png",js="/c/assets/99.Co2KxM6t.png",Qs="/c/assets/100.CaUm8Qhc.png",Js="/c/assets/101.kOkqIKG6.png",Ys="/c/assets/102.CyeASH-c.png",zs="/c/assets/103.CFdk60La.png",Zs="/c/assets/104.Bhl-0uK_.png",sa="/c/assets/105.Dni9KbXV.png",aa="/c/assets/106.BXx10MCV.png",ia="/c/assets/107.CXcIKX1T.png",na="/c/assets/108.CQ3_QCQT.png",la="/c/assets/109.CQoDRJM5.gif",ea="/c/assets/110.CPfwZvD9.gif",pa="/c/assets/111.bxEomEjU.gif",ta="/c/assets/112.C_onhf2k.png",ra="/c/assets/113.Budj3s38.gif",ha="/c/assets/114.CH8koQdu.gif",ca="/c/assets/115.kUJhxMtg.png",da="/c/assets/116.BJeJJW4_.png",oa="/c/assets/117.BCuK6eJL.gif",ka="/c/assets/118.rKC-z4z-.gif",ua="/c/assets/119.BJE3xxuT.gif",ga="/c/assets/120.DJOq__O0.gif",ba="/c/assets/121.BDt_0fRR.png",ma="/c/assets/122.Bo5OawW8.png",Ea="/c/assets/123.sUWUfl5e.png",Ca="/c/assets/124.BK4jpnB8.png",ya="/c/assets/125.EF8vdbSq.png",Fa="/c/assets/126.DjxdA_Co.png",_a="/c/assets/127.sp68q1hh.gif",va="/c/assets/128.DhMRyxNN.gif",Ba="/c/assets/129.CdcLZM0R.gif",Aa="/c/assets/130.D-5AsTTr.png",fa="/c/assets/131.2RQKmAUa.png",xa="/c/assets/132.CI4xX8SM.png",Da="/c/assets/133.C8QUZ9v3.gif",qa="/c/assets/134.g5tQfhWz.gif",Sa="/c/assets/135.CX0_1NsE.gif",wa="/c/assets/136.BrFJeoK6.png",La="/c/assets/137.58TjSSjH.gif",Pa="/c/assets/138.CgqNV2hL.png",Ta="/c/assets/139.BasYWvkM.png",Ua="/c/assets/140.CjFxJpBr.png",Ia="/c/assets/141.Dm5Jspvp.gif",Wa="/c/assets/142.1krCh8cy.gif",Oa="/c/assets/143.DOSyahv7.gif",Na="/c/assets/144.BHEvX_FI.gif",Ra="/c/assets/145.DFA0g1_d.gif",Ma="/c/assets/146.D50nO5eA.gif",Xa="/c/assets/147.cAvG1Qfq.png",Ga="/c/assets/148.DpakQFWz.gif",Va="/c/assets/149.Bg61j9QI.gif",$a="/c/assets/150.DPvD9UCw.gif",Ha="/c/assets/151.Ceu65U_n.gif",Ka="/c/assets/152.BWPFRK_8.gif",ja="/c/assets/153.Ct4TfxPf.gif",Qa="/c/assets/154.zsKtx_jV.png",Ja="/c/assets/155.3oqDAW0w.png",Ya="/c/assets/156.D9TSeAa9.gif",za="/c/assets/157.CCRgYIVq.png",Za="/c/assets/158.C1t2T6FV.gif",si="/c/assets/159.Rqa4uHq6.png",ai="/c/assets/160.6yQYnjOa.gif",ii="/c/assets/161.hYR9GiiD.gif",ni="/c/assets/162.D3b-QIrA.gif",li="/c/assets/163.DGbA6qsW.gif",ei="/c/assets/164.BToOkxf2.gif",pi="/c/assets/166.C3wekjfY.png",ti="/c/assets/167.CKuuzuQ_.png",ri="/c/assets/168.B4r6Nv14.gif",hi="/c/assets/169.CvbhuZNK.png",ci="/c/assets/170.BPgYm4ZX.gif",di="/c/assets/171.DH2fri13.gif",oi="/c/assets/172.CDDIqy03.gif",ki="/c/assets/173.DCQsqYYC.gif",ui="/c/assets/174.CUjMoXNF.gif",gi="/c/assets/175.BWbajkuB.gif",bi="/c/assets/176.C1JnBDr7.png",mi="/c/assets/177.DwN2p3bo.png",Ei="/c/assets/178.DdSfz-Pf.gif",Ci="/c/assets/179.BMocjVt7.gif",yi="/c/assets/180.BUU-wlaw.gif",Fi="/c/assets/181.ssadIF0D.gif",_i="/c/assets/182.Dq5lLq9v.gif",vi="/c/assets/183.CJ0_loZ8.gif",Bi="/c/assets/184.BPOK9irZ.gif",Ai="/c/assets/185.B1eB55rC.gif",fi="/c/assets/186.VIcU-hkN.gif",xi="/c/assets/187.BM9viRZJ.gif",Di="/c/assets/188.DpMBA1SK.gif",qi="/c/assets/189.DgXuU6LF.png",Si="/c/assets/190.Dnw73s2h.gif",wi="/c/assets/191.SnFXRSaL.png",Li="/c/assets/192.DnoEqOjV.png",Pi="/c/assets/193.BJBdn7pw.png",Ti="/c/assets/194.DXtQWYsM.gif",Hi=JSON.parse('{"title":"第一章:计算机组成原理","description":"","frontmatter":{},"headers":[],"relativePath":"notes/01_c-basic/01_xdx/index.md","filePath":"notes/01_c-basic/01_xdx/index.md","lastUpdated":1722823064000}'),Ui={name:"notes/01_c-basic/01_xdx/index.md"},Ii=n('
"电脑"
,是一种能够接收和存储信息,并按照存储在其内部的程序对海量的数据进行自动、高速的处理,然后将处理结果输出的现代化智能电子设备。计算机系统
由硬件(Hardware)系统
和软件(Software)系统
两大部分组成,即:冯·诺依曼
是一位多才多艺的科学家,他在数学、物理学、计算机科学、经济学等领域都有杰出的贡献。冯·诺依曼
的主要成就: 冯·诺依曼
体系结构(1946 年),这是现代计算机设计的基础
。IMPORTANT
冯·诺依曼体系结构
是现代计算机(量子计算机除外)设计的基础
。
冯·诺依曼
体系结构的理论要点如下:
① 存储程序:程序指令
和数据
都存储在计算机的内存中,这使得程序可以在运行时修改。
② 二进制逻辑:所有数据
和指令
都以二进制
形式表示。
③ 顺序执行:指令按照它们在内存中的顺序执行,但可以有条件地改变执行顺序。
④ 五大部件:计算机由运算器
、控制器
、存储器
、输入设备
和输出设备
组成。
⑤ 指令结构:指令由操作码和地址码组成,操作码指示要执行的操作,地址码指示操作数的位置。
⑥ 中心化控制:计算机的控制单元(CPU)负责解释和执行指令,控制数据流。
NOTE
上述的组件协同工作,构成了一个完整的计算机系统:
硬盘
的读写速率已经成为影响系统性能进一 步提高的瓶颈。1 秒 = 1000 毫秒,即 1 s = 1000 ms。
1 毫秒 = 1000 微妙,即 1 ms = 1000 us 。
1 微妙 = 1000 纳秒,即 1 us = 1000 ns。
如果 CPU 的时钟周期按照 1 秒计算,
那么,内存访问就需要 6 分钟;
那么,固态硬盘就需要 2-6 天;
那么,传统硬盘就需要 1-12 个月;
那么,网络访问就需要 4 年以上。
蜉蝣
来表示时间的短暂(和其他生物的寿命比),也是类似的道理,即:鹤寿千岁,以极其游,蜉蝣朝生而暮死,尽其乐,盖其旦暮为期,远不过三日尔。
--- 出自 西汉淮南王刘安《淮南子》
寄蜉蝣于天地,渺沧海之一粟。 哀吾生之须臾,羡长江之无穷。
挟飞仙以遨游,抱明月而长终。 知不可乎骤得,托遗响于悲风。
--- 出自 苏轼《赤壁赋》
NOTE
对于蜉蝣
来说,从早到晚就是一生;而对于我们人类
而言,却仅仅只是一天。
NOTE
上图以层次化的方式,展示了价格信息,揭示了一个真理,即:天下没有免费的午餐(千万不要相信别人会有发财的机会和你共享,人都是自私的,你算个啥?为什么要找你?)
系统调用
:是一套已经写好的代码接口,应用程序通过调用这些接口来请求操作系统执行特定的硬件操作。它们直接与硬件交互,提供底层功能支持,如:文件操作、进程管理、内存管理等。开发者
通过系统调用可以实现对底层资源的直接控制,确保程序能够高效、安全地运行。终端命令
:是一种文本命令接口,通过命令行输入各种指令来控制操作系统和软件的行为。终端命令可以执行文件操作、系统配置、网络管理等各种任务。主要针对开发人员
和高级用户
,他们通过命令行可以快速、精确地完成各种操作,提高工作效率。图形用户界面
(GUI)是通过图形元素(如:窗口、图标、按钮等)与用户进行交互的界面。供直观、易用的操作方式,使用户能够通过鼠标点击、拖拽等简单操作完成复杂任务。主要面向普通用户
,降低了计算机操作的门槛,提高了用户体验和工作效率。用户态(User Mode)
和内核态(Kernel Mode)
是两种不同的执行模式,它们对系统资源的访问权限有着本质的区别。这种区分是为了提供一个稳定和安全的运行环境,防止用户程序直接操作硬件设备和关键的系统资源,从而可能引起系统的不稳定或安全问题。类型 | 内核态(Kernel Mode) | 用户态(User Mode) |
---|---|---|
权限 | 内核态是操作系统代码运行的模式,拥有访问系统全部资源和执行硬件操作的最高权限 。在这种模式下,操作系统的核心部分可以直接访问内存、硬件设备控制、管理文件系统和网络通信等。 | 用户态是普通应用程序运行的模式,具有较低 的系统资源访问权限。在用户态,程序不能直接执行硬件操作,必须通过操作系统提供的接口(即系统调用)来请求服务。 |
安全性 | 由于内核态具有如此高的权限,因此只有可信的、经过严格审查的操作系统核心组件才被允许在此模式下运行。这样可以保护系统不被恶意软件破坏。 | 用户态为系统提供了一层保护,确保用户程序不能直接访问关键的系统资源,防止系统崩溃和数据泄露。 |
功能 | 内核态提供了系统调用 的接口,允许用户态程序安全地请求使用操作系统提供的服务,比如:文件操作、网络通信、内存管理等。 | 用户态保证了操作系统的稳定性和安全性,同时也使得多个程序可以在相互隔离的环境中同时运行,避免相互干扰。 |
NOTE
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class Demo {
public static void writeFile(String filePath, String content) {
Path path = Paths.get(filePath);
try {
Files.write(path, content.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args){
int a = 10; // 用户态
int b = 20; // 用户态
int c = a + b; // 用户态
string filePath = "c:/demo.txt"; // 用户态
string txt = a + b + c; // 用户态
writeFile(filePath, a); // 从用户态切换到内核态完成文件写入
System.out.println(a); // 从内核态切换回用户态
System.out.println(b); // 用户态
System.out.println(c); // 用户态
}
}
NOTE
操作系统层
与由操作系统管理的应用程序
和库
分开。ABI 涵盖了低级数据类型、对齐方式和调用约定等详细信息,并定义了可执行程序的格式。系统调用在此级别定义。此接口允许应用程序和库在实现相同 ABI 的操作系统之间移植。NOTE
PE
(portable executable)格式、.dll
(dynamic link library)格式和 .lib
格式;而在 Linux 上的应用程序的运行格式是:ELF
(executable and linking format)格式、.so
(shared object)格式和 .a
格式。file /bin/ls
命令查看指定可执行应用程序的 ABI 格式;从而也可以论证,在 Windows 上可以运行的程序,在 Linux 上运行不了。一套代码,多平台编译
的方式(针对 C 或 C++ 等),即:相同的源代码,在不同平台(操作系统)上使用特定平台的编译器(如:GCC)来分别编译成符合自己平台的 ABI 规范的二进制文件。应用程序
连接到库
或底层操作系统
。NOTE
系统调用(System Call)
和函数库(Library Call)
的身影,如下:系统调用(System Call)
和函数库(Library Call)
的区别如下:类型 | 系统调用(System Call) | 函数库(Library Call) |
---|---|---|
定义 | 系统调用是操作系统提供给程序员的一组接口,这些接口允许用户空间的程序请求操作系统内核提供的服务,比如文件操作、进程控制、通信和内存管理等。 | 函数库调用是指使用高级语言编写的一组预先编译好的函数,这些函数实现了一些常用的功能,比如:字符串处理、数学计算等。程序员可以在自己的程序中直接调用这些函数,而无需重新实现它们。 |
权限 | 执行系统调用时,会从用户态切换到内核态。这是因为系统调用涉及到访问受保护的系统资源,这些操作必须由操作系统控制以确保系统的稳定性和安全性。 | 函数库调用通常在用户态执行,不涉及到用户态与内核态之间的切换。它们直接使用操作系统通过系统调用提供的服务,或者完全在用户空间内完成计算,不需要操作系统介入。 |
性能开销 | 由于涉及到用户态与内核态之间的切换,系统调用的执行成本相对较高。因此,频繁的系统调用可能会影响程序的性能。 | 相对于系统调用,函数库调用的性能开销较小。因为它们通常不涉及到模式切换,且执行的操作多在用户空间完成。 |
示例 | open(),read(),write(),fork(),exec() 等 UNIX/Linux 系统调用。 | C 标准库中的 printf() 等函数;数学库中的 sin(),cos() 等函数。 |
NOTE
人类语言
是人和人之间用于沟通的一种方式,例如:中国人和中国人之间使用普通话沟通,而中国人和美国人交流,则可以使用英语。计算机编程语言
是人和计算机交流的方式。人们可以使用编程语言
对计算机下达命令(指令)
,让计算机完成人们需要的功能。NOTE
计算机语言有很多种,如:C、C++、Java、Go、JavaScript、Python、Scala 等。
#include <stdio.h> // 这是编译预处理指令
int main() { // 定义主函数
printf("你好,世界!!!"); // 输出所指定的一行信息
return 0; // 函数执行完毕时返回函数值0
}
编写
的程序叫做源代码
,是人类能看懂;但是,计算机却不能识别。那么,我们就需要让计算机能识别我们编写的源程序,就需要将我们编写的源代码交给编译器程序,其会帮助我们将所编写的源代码转换为计算机能够识别的二进制指令。NOTE
编译器就是运行在操作系统之上的程序,其作用就是用来将程序员编写的源代码转换为计算机能够识别的二进制指令。
语法规则
。编译器
程序,将源程序编译为计算机能够识别的二进制指令。ENIAC
诞生,使用的是最原始的穿透卡片
。二进制代码
表示的语言,和人类语言差别极大,这种语言就称为机器语言
,如:0000,0000,000000010000 代表 LOAD A, 16
0000,0001,000000000001 代表 LOAD B, 1
0001,0001,000000010000 代表 STORE B, 16
唯一语言
,人类很难理解;换言之,当时的程序员 99.9% 都是异类!!!IMPORTANT
不同类型(CPU 架构,如:x86_64、arm 等)的处理器有不同的机器语言指令集,指令集架构(ISA)决定了机器语言的具体形式;换言之,机器语言与特定硬件架构紧密相关,机器语言程序几乎没有可移植性。
汇编语言
使用助记符
(如:MOV、ADD、SUB)代替二进制操作码,使程序更易于人类编写和理解;因此,汇编语言
也被称为符号语言
。优点
是能编写高效率
的程序;但是,缺点
和机器语言没什么不同,汇编语言同样依赖于具体的计算机架构(面向机器)
,程序不具备跨平台的可移植性。NOTE
汇编语言,目前仍然应用于工业电子编程领域、软件的加密解密、计算机病毒分析等。
高级语言
是一种接近于人们使用习惯
的程序设计语言。它允许程序员使用接近日常英语的指令来编写程序
,程序中的符号和算式也和日常使用的数学公式
差不多,接近于自然语言和数学语言,容易被人们掌握。独立于计算机硬件
,有一定的通用性;计算机不能直接识别和执行用高级语言编写的程序,需要使用编译器
或解释器
转换为机器语言,才能被计算机识别和执行。NOTE
普遍使用的高级编程语言,有:C、C++、Java、Python、C#、JavaScript、Go、SQL 等。
类别 | 特征 | 优点 | 缺点 | 示例 |
---|---|---|---|---|
机器语言 | 直接由计算机执行的二进制代码 | 执行速度快 | 编写困难,可读性差,与具体硬件强绑定 | 二进制代码 |
汇编语言 | 用助记符代替二进制代码的低级语言 | 相对机器语言更易编写和理解,允许直接控制硬件资源 | 依然需要了解硬件,不够抽象,与具体硬件或平台相关 | MOV,ADD 等助记符 |
高级语言 | 接近人类语言,提供了更高层次的抽象 | 易于编写和维护,可移植性好,支持多种编程范式 | 需要通过编译器或解释器转换为机器语言,可能存在一定的性能损失 | C,Java, Python 等 |
NOTE
肯·汤姆森
(Ken Thompson)和丹尼斯·里奇
(Dennis Ritchie)一起开发了 Unix 操作系统。Unix 最初是使用汇编语言
编写的,依赖于计算机硬件。为了程序的可读性
和可移植性
,它们决定使用高级语言重写。但是。当时的高级语言无法满足他们的要求,肯·汤姆森
就在 BCPL 语言的基础上发明了 B
语言。丹尼斯·里奇
(Dennis Ritchie)在 B
语言的基础上重新设计了一种新的语言,这种新语言取代了 B
语言,即 C
语言。整个 Unix 系统都使用 C 语言重写
。NOTE
C 语言最初是作为 Unix 系统的开发工具而发明的。
C 语言标准化
,标志着 C 语言开始稳定和规范化。C 语言具有可移植好、跨平台的特点
:用 C 语言编写的代码可以在不同的操作系统和硬件平台上编译和运行。NOTE
C 语言的最原始的设计目的,就是为了将 Unix 操作系统移植到其他的计算机架构上,这使得它从一开始就非常注重可移植性。
C 语言在许多领域应用广泛
。 操作系统
:C 广泛用于开发操作系统,如:Unix、Linux 和 Windows。嵌入式系统
:C 是一种用于开发嵌入式系统(如:微控制器、微处理器和其它电子设备)的流程语言。系统软件
:C 用于开发设备驱动程序、编译器和汇编器等系统软件。网络
:C 语言广泛用于开发网络应用程序,例如:Web 服务器、网络协议和网络驱动程序。数据库系统
:C 用于开发数据库系统,例如:Oracle、MySQL 和 PostgreSQL 。游戏
:由于 C 能够处理低级硬件交互,因此经常用于开发计算机游戏。人工智能
:C 用于开发人工智能和机器学习的应用程序,例如:神经网络和深度学习算法。科学应用
:C 用于开发科学应用程序,例如:仿真软件和数值分析工具。金融应用
:C 用于开发股票市场分析和交易系统等金融应用。写需要和硬件交互、有极高性能要求
的程序。学习 C 语言有助于快速上手其他编程语言
,如:C++(原先是 C 语言的一个扩展,在 C 语言的基础上嫁接了面向对象编程思想)、C#、Java 等,这些语言都继承或深受 C 语言的影响和启发。C 语言至今,依然是最广泛使用、最流行的编程语言之一
,包括很多大学将 C 语言作为计算机教学的入门语言,拥有庞大而活跃的用户社区,这意味着有许多资源和库可供开发人员使用。随着微型计算机的日益普及,出现了许多 C 语言版本(标准)。
K
ernighan)和丹尼斯·里奇(Dennis R
itchie)合写了一本著名的教材《C 编程语言》(The C programming language)。NOTE
由于 C 语言还没有成文的语法标准,这本书就成了公认标准,以两位作者的姓氏首字母作为版本简称 “K&R C”。
版本 2(ANSI C,又称 C89 或 C90):C 语言的原始版本非常简单,对很多情况的描述非常模糊,加上 C 语法依然在快速发展,要求将 C 语言标准化的呼声越来越高。1989 年,美国国家标准协会(ANSI)制定了一套 C 语言标准,并于次年被国际标准化组织(ISO)通过。它被称为 “ANSI C”,也可以按照发布年份,称为 “C89 或 C90”。
版本 3(C99):C 语言标准的第一次大型修订
,发生在 1999 年,增加了许多语言特性,比如:双斜杠( // )的注释语法,可变长度数组、灵活的数组成员、复数、内联函数和指定的初始值设定项,这个版本称为 C99,是目前最流行的 C 版本
。
版本 4(C11):2011 年,标准化组织再一次对 C 语言进行修订,增加了_Generic、static_assert 和原子类型限定符。这个版本称为 C11。
NOTE
需要强调的是,修订标准的原因并不是因为原标准不能用,而是需要跟进新的技术。
需要注意的是,C 语言的标准并没有强制性的约束,只是个说明文档而已。不同的编译器产商,对 C 语言的标准有不同的实现,甚至会出现某些 C 语言的标准在这个编译器下实现了;但是,在另外的编辑器下却没有实现,导致编译程序错误的现象。常见的 C/C++ 编译器如下:
IMPORTANT
GCC 编译套件对标准的支持是最好的;所以,在实际项目开发中,我们首先会选用 GCC 编译套件来进行开发。
C 语言的优点:
C 语言的缺点:
总而言之,C 语言的高效性和灵活性使其在系统级编程和嵌入式系统中占据重要地位,但其缺乏高级特性和内存管理上的挑战也使得开发过程可能更加复杂和容易出错。对于需要高性能和底层控制的应用,C 语言依然是不可替代的选择。
要开发 C/C++ 程序,需要安装 C/C++ 编译器,目前有两种主流实现,即:
GCC 在 Windows 上的版本有很多,如:MinGW-w64、Gygwin、MSYS2。它们之间的区别,如下所示:
特性 | MinGW-w64 | Cygwin | MSYS2 |
---|---|---|---|
简介 | Minimalist GNU for Windows | POSIX 兼容环境和工具集 | 结合了 MinGW 和 Cygwin 的工具集 |
编译器 | 提供 GCC 编译器 | 提供 POSIX 兼容环境,包含大量工具 | 提供 MinGW-w64 工具链和 Cygwin 环境 |
生成文件 | Windows 原生可执行文件 | POSIX 兼容的可执行文件 | 可以生成 Windows 原生可执行文件或 POSIX 文件 |
依赖 | 无需额外依赖 | 依赖 Cygwin DLL | 根据使用工具链决定(MinGW-w64 无依赖,Cygwin 有依赖) |
工具和库 | 基本的编译工具 | 丰富的 Unix 工具和库 | 丰富的工具和库,强大的包管理系统 |
性能 | 性能较好 | 可能较低,因为通过兼容层调用系统 | 取决于使用的工具链(MinGW-w64 性能较好) |
复杂度 | 简单易用 | 设置和使用相对复杂 | 较为灵活,复杂度介于 MinGW-w64 和 Cygwin 之间 |
适用场景 | 开发 Windows 原生应用 | 运行和开发 Unix 程序 | 混合使用 Unix 工具和开发 Windows 原生应用 |
优点 | 轻量级,直接生成 Windows 应用 | 完整的 POSIX 兼容环境,丰富的工具 | 灵活的环境,强大的包管理系统 |
缺点 | 工具和库较少 | 生成文件依赖 Cygwin DLL,性能可能较低 | 环境较大,占用更多空间,复杂性比 MinGW-w64 高 |
NOTE
NOTE
下载地址在这里。
NOTE
本人的解压目录是:D:\\develop\\mingw64
。
NOTE
因为,本人安装 MinGW-w64 的目录是 D:\\develop\\mingw64
,所以配置 path 环境变量就需要 D:\\develop\\mingw64\\bin
。
gcc --version
NOTE
下载地址在这里。
NOTE
默认是最小化安装,没有 GCC,需要选择 gcc-core、gcc-g++、make、gdb、binutils 。
3.1.2.2 配置 path 环境变量
步骤相同:略。NOTE
下载地址在这里。
sed -i "s#https\\?://mirror.msys2.org/#https://mirrors.tuna.tsinghua.edu.cn/msys2/#g" /etc/pacman.d/mirrorlist*
pacman -Syu --noconfirm # 更新包管理器
pacman -Sy base-devel --noconfirm # 安装开发工具包
pacman -Sy mingw-w64-x86_64-toolchain --noconfirm # 安装开发 gcc 相关工具链
3.1.2.2 配置 path 环境变量
步骤相同:略。自动保存
功能:文件编码
为 UTF-8:控制台编码
为 UTF-8:显示方法分隔符
功能:编辑器
的字体(可选):NOTE
Visual Studio Code 需要安装对应的插件,才能运行 C/C++ 代码。
中文
插件:C/C++
插件:Visual Studio(简称 VS)是由微软公司发布的集成开发环境。它包括了整个软件生命周期中所需要的大部分工具,如:UML工具、代码管控工具、集成开发环境(IDE)等。
Visual Studio 支持 C/C++、C#、F#、VB 等多种程序语言的开发和测试,可以用于生成Web应用程序,也可以生成桌面应用程序,功能十分强大,但下载和安装很可能耗时数小时,还可能会塞满磁盘。
Visual Studio 2022 有三种版本:社区版(免费,不支持企业使用),专业版(第一年 1199 美元/ 799 美元续订)和企业版(第一年 5999 美元/ 2569 美元续订)。企业版拥有面向架构师的功能、高级调试和测试,这些功能是另两种 SKU 所没有的。
Visual Studio 旨在成为世界上最好的 IDE(集成开发环境),目前最新版本为 Visual Studio 2022。
共享组件、工具和 SDK
不可以修改,即:注册表编辑器
,将如下图中的除了第一个选项,全部删除,然后关闭再重新安装,即:NOTE
TD244-P4NB7-YQ6XK-Y8MMM-YWV2J
VHF9H-NXBBB-638P6-6JHCY-88JWH
HelloWorld.c
的文件:记事本
等软件打开该文件,输入如下的代码,并保存:#include <stdio.h>
int main(){
printf("Hello World");
return 0;
}
gcc
命令编译该文件:gcc HelloWorld.c -o HelloWorld.exe
./HelloWorld.exe
空
文件夹(目录),用于存放代码:vscode
打开该目录:vscode
中新建 HelloWorld.c
文件:#include <stdio.h>
int main(){
printf("Hello World");
return 0;
}
gcc
命令编译该文件:gcc HelloWorld.c -o HelloWorld.exe
./HelloWorld.exe
解决方案资源管理器
:HelloWorld.c
文件:#include <stdio.h>
int main(){
printf("Hello World");
return 0;
}
#include <stdio.h>
int main(){
printf("Hello World");
return 0;
}
NOTE
内容如下所示:
-Dfile.encoding=UTF-8
-Dconsole.encoding=UTF-8
注释
是一种特殊
的文本,它不会被编译器执行,而仅用于代码的解释和文档说明。NOTE
注释
整理出来,然后再用代码
去实现。// 单行注释
NOTE
在 CLion 中的快捷键是 Ctrl + /
。
#include <stdio.h> // 这是编译预处理指令
int main() { // 定义主函数
printf("你好,世界!!!"); // 输出所指定的一行信息
return 0; // 函数执行完毕时返回函数值0
}
/*
这是第一行注释
这是第二行注释
这是第三行注释
*/
NOTE
Ctrl + Alt + /
。#include <stdio.h>
int main() {
/*
printf(1);
printf(2);
*/
printf("你好,世界!!!");
return 0;
}
tab
操作,实现缩进,默认整体向右边移动;如果使用 shift + tab
则整体向左移动。2 + 4 = 6
。NOTE
各种 IDE 都有格式化的快捷键,如:CLion 的格式化快捷键是 Ctrl + Alt + L
。
#include <stdio.h>
int main() {
int a = 1;
int b = 2;
int c = a + b;
printf("c = %d", c);
return 0;
}
行尾风格
和次行风格
。NOTE
看个人爱好,任选一种即可,本人喜欢行尾分格
!!!
int main(){
if(a > b) {
return a;
} else {
return b;
}
return 0;
}
int main()
{
if(a > b)
{
return a;
}
else
{
return b;
}
return 0;
}
int main(){
return 0;
}
int
称为关键字,代表数据类型是整型
,它是 main() 函数的返回值的类型,即在执行 main() 函数之后一定会得到一个整数类型的值,即函数值。NOTE
return 0
,就表示 main() 函数终止运行,且运行成功;如果返回其它非零整数,则表示运行失败。return 0
,则编译器会自动加上;但是,为了保持统一的代码风格,不建议省略。{}
定义了函数的主体,所有函数都必须以大括号开头和结尾,成对出现。;
作为语句结束的标志。printf (const char *__format, ...)
printf ("Hello World"); // 将字符串输出到控制台,行尾不换行
\\n
,即:printf("Hello World\\n");
stdio.h
中定义的,要想在程序中使用这个函数,必须在源文件的头部引入该头文件,即:#include <stdio.h>
标准库
是由一组函数组成,这些函数提供了许多常用的操作和功能,如:输入输出、字符串处理、内存管理、数学计算等。标准库中的函数由编译器提供,遵循 ANSI C 标准(如:C89/C90、C99、C11等)。标准库
就是包含函数的实际代码,这些代码在编译的时候被链接到我们的程序中,无需手动包含。C 语言的标准库
提供了可重用的函数实现,使得程序员不必编写常用的功能。NOTE
实际的 printf() 函数的实现代码通常位于标准库的实现文件中,如:在 Linux 中的标准库libc.so.6
就包含了 printf() 函数的实现。
头文件
是包含函数声明、宏定义、数据类型定义等内容的文件。头文件的作用是为源代码提供必要的声明和定义,以便编译器能够正确解析和链接函数调用。头文件通常以.h
作为文件扩展名。
换言之,头文件包含函数声明、宏定义和数据类型定义,但不包含函数的实现。头文件告知编译器如何使用标准库中的函数和定义,确保编译时的正确性。头文件需要在源代码文件中使用#include
指令显式包含,如:#include <stdio.h>
。
常见的 C 语言头文件及其功能和常用函数、宏等,如下所示:
头文件 | 功能说明 | 常用函数和宏 |
---|---|---|
stdio.h | 标准输入输出库 | printf , scanf , fprintf ,fscanf ,fopen , fclose ,fgets , fputs |
stdlib.h | 标准库,提供内存分配、程序控制、类型转换、随机数生成等功能 | malloc , free , exit , atoi , atof ,rand ,srand |
string.h | 字符串处理库 | strlen , strcpy , strncpy , strcat , strcmp ,strstr , memset , memcpy |
math.h | 数学库 | sin , cos , tan , exp , log , sqrt , pow |
time.h | 时间和日期库 | time , clock , difftime , mktime , strftime , localtime ,gmtime |
ctype.h | 字符处理库 | isalnum , isalpha , isdigit , islower , isupper , tolower , toupper |
stdbool.h | 布尔类型库 | bool , true , false |
assert.h | 断言库 | assert |
#include
命令的作用是将指定文件的内容插入到包含该命令的源文件中。这通常用于包含头文件,以便使用头文件中声明的函数、宏和数据类型。// 用于包含标准库头文件或系统头文件。
// 编译器将在系统的标准头文件目录中查找文件。
#include <filename>
// 用于包含用户自定义的头文件。
// 编译器首先在当前目录中查找文件,如果未找到,再在标准头文件目录中查找。
#include "filename"
WSL2 的功能,如下所示:
WSL 的用途,如下所示:
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
IMPORTANT
以管理员身份打开 PowerShell 并运行,执行完上述命令之后,如果提示需要重启计算机,那就重启计算机。
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
IMPORTANT
以管理员身份打开 PowerShell 并运行,执行完上述命令之后,如果提示需要重启计算机,那就重启计算机。
wsl --update
NOTE
wsl2 的最新 Linux 内核包托管在 GitHub 上,某些国家可能会污染 Github 相关的域名,那么就需要手动下载,然后安装即可,下载地址在这里。
wsl --set-default-version 2
wsl --list --online
wsl --install Ubuntu-24.04
NOTE
官方支持的 Linux 版本,托管在 Github 上,某些国家可能会污染 Github 的域名;此时,要么走科学上网,要么在 Microsoft Store
中搜索并安装。
wsl --list
sudo dnf update -y # 更新包管理器
sudo dnf groupinstall "Development Tools" -y # 安装开发工具包
sudo dnf install gcc gcc-c++ -y # 安装GCC相关工具链
sudo dnf install cmake -y # 安装 cmake
sudo dnf install make -y # 安装 make
sudo dnf install gdb -y # 安装 gdb
sudo apt update && sudo apt upgrade -y # 更新包管理器
sudo apt install build-essential -y # 安装开发工具包
sudo apt install gcc g++ -y # 安装 GCC 相关工具链
sudo apt install cmake -y # 安装 cmake
sudo apt install gdb -y # 安装 gdb
NOTE
默认仓库中的 GDB 的版本会很高,CLion 会不支持,那么就需要手动下载源码,自行编译,本次不再演示!!!
CMakeLists.txt
文件的内容,以便其支持在一个 C 语言项目中,可以有多个包含 main() 函数的文件,如下所示:CMakeLists.txt
的内容,如下所示:cmake_minimum_required(VERSION 3.10)
# 项目名称和版本号
project(c-study VERSION 1.0 LANGUAGES C)
# 设置 C 标准
set(CMAKE_C_STANDARD 23)
set(CMAKE_C_STANDARD_REQUIRED True)
# 辅助函数,用于递归查找所有源文件
function(collect_sources result dir)
file(GLOB_RECURSE new_sources "\${dir}/*.c")
set(\${result} \${\${result}} \${new_sources} PARENT_SCOPE)
endfunction()
# 查找顶层 include 目录(如果存在)
if (EXISTS "\${CMAKE_SOURCE_DIR}/include")
include_directories(\${CMAKE_SOURCE_DIR}/include)
endif ()
# 查找所有源文件
set(SOURCES)
collect_sources(SOURCES \${CMAKE_SOURCE_DIR})
# 用于存储已经处理过的可执行文件名,防止重复
set(EXECUTABLE_NAMES)
# 创建可执行文件
foreach (SOURCE \${SOURCES})
# 获取文件的相对路径
file(RELATIVE_PATH REL_PATH \${CMAKE_SOURCE_DIR} \${SOURCE})
# 将路径中的斜杠替换为下划线,生成唯一的可执行文件名
string(REPLACE "/" "_" EXECUTABLE_NAME \${REL_PATH})
string(REPLACE "\\\\" "_" EXECUTABLE_NAME \${EXECUTABLE_NAME})
string(REPLACE "." "_" EXECUTABLE_NAME \${EXECUTABLE_NAME})
# 处理与 CMakeLists.txt 文件同名的问题
if (\${EXECUTABLE_NAME} STREQUAL "CMakeLists_txt")
set(EXECUTABLE_NAME "\${EXECUTABLE_NAME}_exec")
endif ()
# 检查是否已经创建过同名的可执行文件
if (NOT EXECUTABLE_NAME IN_LIST EXECUTABLE_NAMES)
list(APPEND EXECUTABLE_NAMES \${EXECUTABLE_NAME})
# 创建可执行文件
add_executable(\${EXECUTABLE_NAME} \${SOURCE})
# 查找源文件所在的目录,并添加为包含目录(头文件可能在同一目录下)
get_filename_component(DIR \${SOURCE} DIRECTORY)
target_include_directories(\${EXECUTABLE_NAME} PRIVATE \${DIR})
# 检查并添加子目录中的 include 目录(如果存在)
if (EXISTS "\${DIR}/include")
target_include_directories(\${EXECUTABLE_NAME} PRIVATE \${DIR}/include)
endif ()
# 检查并添加 module 目录中的所有 C 文件(如果存在)
if (EXISTS "\${DIR}/module")
file(GLOB_RECURSE MODULE_SOURCES "\${DIR}/module/*.c")
target_sources(\${EXECUTABLE_NAME} PRIVATE \${MODULE_SOURCES})
endif ()
endif ()
endforeach ()
.clang-format
格式化文件,以便写代码的时候,可以自动保存并格式化 C 程序代码,如下所示:.clang-format
的内容,如下所示:BasedOnStyle: Google
IndentWidth: 4
UseTab: Never
ColumnLimit: 0
# 控制大括号的位置
BreakBeforeBraces: Attach
# 控制空行的使用
EmptyLineBeforeAccessModifier: Never
KeepEmptyLinesAtTheStartOfBlocks: true
# 控制短函数、短 if 语句和循环的格式
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
# 控制其他格式选项
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
# 控制注释的格式化
ReflowComments: true
# 控制包含指令的格式化
IncludeBlocks: Regroup
SortIncludes: CaseInsensitive
SpaceBeforeParens: ControlStatements
SpacesInParentheses: false
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
保存
的时候自动格式化
,即:.gitignore
文件,以便在提交代码到 Git 仓库的时候,忽略某些文件或目录,如下所示:.gitignore
文件的内容,如下所示:.vscode
.idea
cmake-build-*
build
NOTE
如果是复制并粘贴一个文件到项目中,请点击重新加载 CMake 项目
!!!
IMPORTANT
源程序需要以 .c
作为扩展名。
目标程序(或目标文件)
。如果程序没有错误,没有任何提示,就会生成一个扩展名为 .obj
或 .o
的二进制文件。C 语言中的每条可执行语句经过编译之后,最终都会转换为二进制的机器指令。IMPORTANT
① 其实,编译阶段
包含了预处理
、编译
和汇编
。
② 预处理
是编译过程的第一个阶段。在这个阶段,预处理器处理源代码中的指令(例如:#include
、#define
等),主要任务包括:
头文件包含:将头文件的内容插入到源文件中。例如:#include <stdio.h>
会被替换为stdio.h
文件的内容。
宏展开:替换宏定义。例如:#define PI 3.14
会将代码中的PI
替换为3.14
。
条件编译:根据条件指令(如:#ifdef
、#ifndef
)有选择地编译代码。
删除代码中的注释,但是不会进行语法检查。
预处理完成后,生成一个扩展名为.i
的中间文件。
③ 编译
是将预处理后的源代码转换为汇编代码的过程。在这个阶段,编译器会检查代码的语法和语义,将其转换为目标机器的汇编语言,生成一个扩展名为.s
的汇编文件。
④ 汇编
是将汇编代码转换为机器代码(也称为目标代码或目标文件)的过程。在这个阶段,汇编器将汇编指令转换为二进制机器指令,生成一个扩展名为.o
或 .obj
的目标文件。
*.obj
或 *.o
和库函数以及其他目录文件链接
,形成一个统一的二进制文件 *.exe
。IMPORTANT
<stdio.h>
中的 printf()
函数,这些函数不是程序员自己写的,而是 C 程序库中提供的,因此需要链接。其实,在链接过程中,还会加入启动代码,这个启动代码(和系统相关,Linux 下主要有 crt0.c、crti.c 等,它们设置堆栈后,再调用 main() 函数)负责初始化程序运行时的环境。*.exe
文件,我们就可以在控制台上执行运行此 *.exe
文件。IMPORTANT
如果修改
了源代码,还需要重新编译
、链接
,并生成新的 *.exe
文件,再执行,方能生效。
gcc HelloWorld.c -o HelloWorld.exe
gcc -E 源文件.c -o 源文件.i # 通常以 .i 结尾表示这个文件是一个中间状态
gcc -S 源文件.i -o 源文件.s # 在 Linux 中,通常以 .s 结尾;在 Windows 中,通常以 .asm 结尾
gcc -c 源文件.s -o 源文件.o # 在 Linux 中,通常以 .o 结尾;在 Windows 中,通常以 .obj 结尾
gcc 源文件.o -o 源文件.exe # 在 Linux 中,通常以 .out 结尾;在 Windows 中,通常以 .exe 结尾
gcc -E HelloWorld.c -o HelloWorld.i
gcc -S HelloWorld.i -o HelloWorld.s
gcc -c HelloWorld.s -o HelloWorld.o
gcc HelloWorld.o -o HelloWorld.exe
%USERPROFILE%\\.wslconfig
文件,内容如下:[wsl2]
networkingMode=mirrored
dnsTunneling=true
firewall=true
autoProxy=true
[experimental]
# requires dnsTunneling but are also OPTIONAL
bestEffortDnsParsing=true
useWindowsDnsCache=true
wsl --shutdown
printf
函数或 scanf
函数很正常,如下所示:printf
函数或 scanf
函数会一直没有输出,如下所示:scanf
函数并不是直接让用户从键盘输入数据,而是先检查缓冲区,处理缓冲区中的数据;当遇到 scanf
函数时,程序会先检查输入缓冲区中是否有数据,所以解决方案就是禁用缓冲区
,如下所示:#include <stdio.h>
int main() {
// 禁用 stdout 缓冲区
setbuf(stdout, NULL);
int a, b, c;
printf("请输入整数 a 、b 和 c 的值:");
scanf("%d %d %d", &a, &b, &c);
int result = a * b * c;
printf("%d × %d × %d = %d", a, b, c, result);
return 0;
}
Valgrind
项目来进行内存泄露检测
和性能分析
,而 Valgrind
只支持 Linux 。NOTE
win 11 中的 WSL2 就是个 Linux 环境,我们可以在上面跑各种 Linux 工具,这样我们就不需要再安装虚拟机软件了,如:VMware Workstation(它会完整的模拟一个硬件系统,并在上面跑各种 Linux ,实在是太笨重了)。
dnf -y upgrade && dnf -y install valgrind # AlmaLinux
apt -y update && apt -y upgrade && apt -y install valgrind # Ubuntu
which valgrind
cmake --version
cmake_minimum_required(VERSION 3.26.5) # 3.26.5
# 项目名称和版本号
project(c-study VERSION 1.0 LANGUAGES C)
# 设置 C 标准
set(CMAKE_C_STANDARD 23)
set(CMAKE_C_STANDARD_REQUIRED True)
# 辅助函数,用于递归查找所有源文件
function(collect_sources result dir)
file(GLOB_RECURSE new_sources "\${dir}/*.c")
set(\${result} \${\${result}} \${new_sources} PARENT_SCOPE)
endfunction()
# 查找顶层 include 目录(如果存在)
if (EXISTS "\${CMAKE_SOURCE_DIR}/include")
include_directories(\${CMAKE_SOURCE_DIR}/include)
endif ()
# 查找所有源文件
set(SOURCES)
collect_sources(SOURCES \${CMAKE_SOURCE_DIR})
# 用于存储已经处理过的可执行文件名,防止重复
set(EXECUTABLE_NAMES)
# 创建可执行文件
foreach (SOURCE \${SOURCES})
# 获取文件的相对路径
file(RELATIVE_PATH REL_PATH \${CMAKE_SOURCE_DIR} \${SOURCE})
# 将路径中的斜杠替换为下划线,生成唯一的可执行文件名
string(REPLACE "/" "_" EXECUTABLE_NAME \${REL_PATH})
string(REPLACE "\\\\" "_" EXECUTABLE_NAME \${EXECUTABLE_NAME})
string(REPLACE "." "_" EXECUTABLE_NAME \${EXECUTABLE_NAME})
# 处理与 CMakeLists.txt 文件同名的问题
if (\${EXECUTABLE_NAME} STREQUAL "CMakeLists_txt")
set(EXECUTABLE_NAME "\${EXECUTABLE_NAME}_exec")
endif ()
# 检查是否已经创建过同名的可执行文件
if (NOT EXECUTABLE_NAME IN_LIST EXECUTABLE_NAMES)
list(APPEND EXECUTABLE_NAMES \${EXECUTABLE_NAME})
# 创建可执行文件
add_executable(\${EXECUTABLE_NAME} \${SOURCE})
# 查找源文件所在的目录,并添加为包含目录(头文件可能在同一目录下)
get_filename_component(DIR \${SOURCE} DIRECTORY)
target_include_directories(\${EXECUTABLE_NAME} PRIVATE \${DIR})
# 检查并添加子目录中的 include 目录(如果存在)
if (EXISTS "\${DIR}/include")
target_include_directories(\${EXECUTABLE_NAME} PRIVATE \${DIR}/include)
endif ()
# 检查并添加 module 目录中的所有 C 文件(如果存在)
if (EXISTS "\${DIR}/module")
file(GLOB_RECURSE MODULE_SOURCES "\${DIR}/module/*.c")
target_sources(\${EXECUTABLE_NAME} PRIVATE \${MODULE_SOURCES})
endif ()
endif ()
endforeach ()
perf
是一个 Linux 下的性能分析工具,主要用于监控和分析系统性能。它可以帮助开发者和系统管理员了解系统中哪些部分在消耗资源、识别性能瓶颈以及分析程序的运行效率。dnf -y install perf
apt -y update \\
&& apt -y install linux-tools-common linux-tools-generic linux-tools-$(uname -r)
NOTE
之所以报错的原因,在于 WSL2 中的 Ubuntu 的内核是定制化的,并非 Ubuntu 的母公司 Canonical 发布的标准内核,所以需要我们手动编译安装。
uname -sr
export KERNEL_VERSION=$(uname -r | cut -d'-' -f1)
apt -y update && \\
apt -y install binutils-dev debuginfod default-jdk default-jre libaio-dev \\
libbabeltrace-dev libcap-dev libdw-dev libdwarf-dev libelf-dev libiberty-dev \\
liblzma-dev libnuma-dev libperl-dev libpfm4-dev libslang2-dev libssl-dev \\
libtraceevent-dev libunwind-dev libzstd-dev libzstd1 python3-setuptools python3 \\
python3-dev systemtap-sdt-dev zlib1g-dev bc dwarves bison flex libnewt-dev libdwarf++0 \\
libelf++0 libbfb0-dev python-dev-is-python3
git clone \\
--depth 1 \\
--single-branch --branch=linux-msft-wsl-\${KERNEL_VERSION} \\
https://github.com/microsoft/WSL2-Linux-Kernel.git
cd WSL2-Linux-Kernel
make -j $(nproc) KCONFIG_CONFIG=Microsoft/config-wsl
cd tools/perf
make clean && make
cp perf /usr/bin/
中文乱码
问题,就需要去语言和区别
设置系统区域
的编码为 UTF-8 ;但是,这样可能会造成其它的软件出现中文乱码问题,如:Xshell 等。NOTE