0%

简介

  • RESTful接口相关笔记
  • 表现层状态转换(Representational State Transfer, REST)

表现层状态转换

  • 表现层状态转换(英语:Representational State Transfer,缩写:REST)是Roy Thomas Fielding博士于2000年在他的博士论文[1]中提出来的一种万维网软件架构风格,目的是便于不同软件/程序在网络(例如互联网)中互相传递信息。表现层状态转换是根基于超文本传输协议(HTTP)之上而确定的一组约束和属性,是一种设计提供万维网络服务的软件构建风格。符合或兼容于这种架构风格(简称为 REST 或 RESTful)的网络服务,允许客户端发出以统一资源标识符访问和操作网络资源的请求,而与预先定义好的无状态操作集一致化。因此表现层状态转换提供了在互联网络的计算系统之间,彼此资源可交互使用的协作性质(interoperability)。相对于其它种类的网络服务,例如SOAP服务,则是以本身所定义的操作集,来访问网络上的资源。

  • 目前在三种主流的Web服务实现方案中,因为REST模式与复杂的SOAP和XML-RPC相比更加简洁,越来越多的Web服务开始采用REST风格设计和实现。例如,Amazon.com提供接近REST风格的Web服务执行图书查询;雅虎提供的Web服务也是REST风格的。

要点及标准

  • 需要注意的是,REST是设计风格而不是标准。REST通常基于HTTP、URI、XML以及HTML这些现有的广泛流行的协议和标准。

  • 资源是由URI来指定。

  • 对资源的操作包括获取、创建、修改和删除,这些操作正好对应HTTP协议提供的GET、POST、PUT和DELETE方法。

  • 通过操作资源的表现形式来操作资源。

  • 资源的表现形式则是XML或者HTML,取决于读者是机器还是人、是消费Web服务的客户软件还是Web浏览器。当然也可以是任何其他的格式,例如JSON。

  • 可重新表达的状态迁移的特征

    • Uniform Interface:统一接口。
      • 以资源为基础
        • 每个资源都可以通过URI访问到。
        • 也就是一个个可以认知的资源,比如文档,音乐,视频等信息,都可以通过唯一的URI确定。
      • 通过重表达的客户端可以管理原资源
        • 就是我们通过客户端可以修改原资源的状态。
      • 返回信息足够描述自己
        • 这样重表达的客户端可以知道如何处理。
      • 超媒体是应用状态的引擎
        • 处理以超媒体为基础的状态变化。
    • Stateless:无状态。
    • Cacheable:可缓存。
    • Client-Server:客户服务器分离模式,任何一个客户端与服务器都是可替换的。
    • Layered System:分层的系统,客户端不知道他联系的是不是最终服务器。
    • Code on Demand(可选):服务器可以将能力扩展到客户端,如果客户端可以执行的话。这个功能是可选择的

REST架构的限制条件

  • REST架构风格最重要的架构限制有6个:
    1. 客户端-服务器(Client-Server)
    • 客户端-服务器结构限制的目的是将客户端和服务器端的关注点分离。将用户界面所关注的逻辑和数据存储所关注的逻辑分离开来有助于提高用户界面的跨平台的可移植性。通过简化服务器模块也有助于服务器模块的可扩展性。
    1. 无状态(Stateless)
    • 服务器不能保存客户端的信息;每一次从客户端发送的请求中,要包含所有的必须的状态信息,会话信息由客户端保存,服务器端根据这些状态信息来处理请求。
    • 服务器可以将会话状态信息传递给其他服务,比如数据库服务,这样可以保持一段时间的状态信息,从而实现认证功能。
    • 当客户端可以切换到一个新状态的时候发送请求信息。
    • 当一个或者多个请求被发送之后,客户端就处于一个状态变迁过程中。每一个应用的状态描述可以被客户端用来初始化下一次的状态变迁。
    1. 缓存(Cacheability)
    • 如同万维网一样,客户端和中间的通讯传递者可以将回复缓存起来。回复必须明确的或者间接的表明本身是否可以进行缓存,这可以预防客户端在将来进行请求的时候得到陈旧的或者不恰当的数据。管理良好的缓存机制可以减少客户端-服务器之间的交互,甚至完全避免客户端-服务器交互,这进一步提了高性能和可扩展性
    1. 统一接口(Uniform Interface)
    • 这是 RESTful 系统设计的基本出发点。它简化了系统架构,减少了耦合性,可以让所有模块各自独立的进行改进。包括下列四个限制:
      • 请求中包含资源的 ID(Resource identification in requests)
        • 请求中包含了各种独立资源的标识,例如,在Web服务中的URI。资源本身和发送给客户端的标识是独立。例如,服务器可以将自身的数据库信息以HTML、XML或者JSON的方式发送给客户端,但是这些可能都不是服务器的内部记录方式。
      • 资源通过标识来操作(Resource manipulation through representations)
        • 当客户端拥有一个资源的标识,包括附带的元数据,则它就有足够的信息来删除这个资源。
      • 消息的自我描述性(Self-descriptive messages)
        • 每一个消息都包含足够的信息来描述如何来处理这个信息. 例如,媒体类型 (media-type) 就可以确定需要什么样的分析器来分析媒体数据.
      • 用超媒体驱动应用状态(Hypermedia as the engine of application state (HATEOAS))
        • 同用户访问Web服务器的Home页面相似,当一个 REST 客户端访问了最初的REST应用的URI之后,REST 客户端应该可以使用服务器端提供的链接,动态的发现所有的可用的资源和可执行的操作。随着访问的进行,服务器在响应中提供文字超链接,以便客户端可以得到当前可用的操作。客户端无需用确定的编码的方式记录下服务器端所提供的动态应用的结构信息
    1. 分层系统(Layered System)
    • 客户端一般不知道是否直接连接到了最终的服务器,或者是路径上的中间服务器。中间服务器可以通过负载均衡和共享缓存的机制提高系统的可扩展性,这样可也便于安全策略的部署
    1. 按需代码(Code-On-Demand, 可选)
    • 服务器可以通过发送可执行代码给客户端的方式临时性的扩展功能或者定制功能,例如Java Applet、Flash或JavaScript。

关于状态

  • 应该注意区别应用的状态和连接协议的状态。HTTP连接是无状态的(也就是不记录每个连接的信息),而REST传输会包含应用的所有状态信息,因此可以大幅降低对HTTP连接的重复请求资源消耗

REST的优点

  • 可更高效利用缓存来提高响应速度
  • 通讯本身的无状态性可以让不同的服务器的处理一系列请求中的不同请求,提高服务器的扩展性
  • 浏览器即可作为客户端,简化软件需求
  • 相对于其他叠加在HTTP协议之上的机制,REST的软件依赖性更小
  • 不需要额外的资源发现机制
  • 在软件技术演进中的长期的兼容性更好

简介

  • repo工具的笔记

详解

在Linux系统中,”repo” 是一个版本控制工具,用于协调多个Git存储库的管理和同步。它是Google为了管理Android开源项目而开发的,但也可用于其他项目。

repo工具基于Python编写,它提供了一个简化的方式来处理包含多个Git存储库的项目。使用repo工具,您可以轻松地进行跨多个存储库的代码同步、分支管理和代码审查等操作。

以下是repo工具的一些常见用法和功能:

  1. 安装repo:要使用repo工具,您首先需要安装它。通常,您可以从Linux发行版的软件仓库中安装repo软件包。例如,在Ubuntu上可以使用以下命令安装repo:

    1
    sudo apt-get install repo
  2. 初始化项目:要在一个新项目中使用repo工具,您需要创建一个包含一个特殊的仓库清单(manifest)文件的目录。这个清单文件描述了项目中的所有Git存储库以及它们的分支、路径等信息。然后,使用以下命令初始化项目:

    1
    repo init -u <manifest-url>

    其中,<manifest-url>是指向清单文件的URL。

  3. 同步代码:一旦项目初始化完成,您可以使用以下命令将代码同步到本地工作区:

    1
    repo sync

    这将根据清单文件中定义的分支和路径,将各个Git存储库的代码下载到本地。

  4. 创建分支:使用repo工具可以轻松创建和切换Git分支。例如,要创建一个名为mybranch的分支,可以执行以下命令:

    1
    repo start mybranch --all

    这将在所有Git存储库中创建名为mybranch的新分支。

  5. 提交更改:在进行代码更改后,可以使用普通的Git命令将更改提交到特定的存储库。例如:

    1
    2
    3
    cd <repository-directory>
    git add .
    git commit -m "Commit message"

    然后,使用repo upload命令将提交的更改推送到相应的存储库。

这只是repo工具的一些基本用法,它还提供了其他功能,例如管理代码分支、处理代码审查等。您可以通过运行repo help命令获取更多的帮助和使用说明。

请注意,repo工具主要用于管理包含多个Git存储库的大型项目,因此在小型项目或单个存储库的情况下,可能没有必要使用repo工具。

简介

  • 机器人相关的理论基础知识

轴角

轴角(Axis-Angle)表示是一种用于描述三维空间中旋转的方法,它使用一个旋转轴的方向向量和一个旋转角度来表示旋转操作。轴角表示法具有直观性和数学简洁性,尤其在对大角度旋转和连续旋转的情况下很有用。

以下是轴角表示法的一些详细说明:

1. 旋转轴向量: 旋转轴向量是一个单位向量,它指示了围绕它进行旋转的轴的方向。通常用一个三维向量 ( \mathbf{v} = (x, y, z) ) 表示。这个向量不仅指明了旋转的方向,还表明了旋转的轴在三维空间中的位置。

2. 旋转角度: 旋转角度是旋转操作的大小,通常以弧度为单位来度量。它决定了围绕旋转轴旋转多少弧度。正值表示逆时针旋转,负值表示顺时针旋转。

3. 旋转矩阵: 使用轴角表示旋转,可以通过旋转矩阵来表示旋转操作。旋转矩阵是一个 3x3 的矩阵,它描述了绕指定轴旋转指定角度的操作。可以使用 Rodrigues 公式将轴角转换为旋转矩阵。公式如下:

[ \mathbf{R} = \mathbf{I} + \sin(\theta)\mathbf{K} + (1 - \cos(\theta))\mathbf{K}^2 ]

其中 ( \mathbf{R} ) 是旋转矩阵,( \mathbf{I} ) 是单位矩阵,( \theta ) 是旋转角度,( \mathbf{K} ) 是由旋转轴向量构建的反对称矩阵。

4. 应用领域: 轴角表示法在计算机图形学、计算机动画、机器人学等领域中得到广泛应用。它特别适用于模拟物体的旋转运动,例如在计算机游戏中模拟角色的转身、飞行器的定向等。

5. 优点和缺点: 轴角表示法在大角度旋转情况下更加稳定,不会遇到欧拉角中的万向节死锁问题。然而,对于描述连续旋转过程,它可能不如四元数(Quaternions)表示法那么方便,因为连续旋转的组合操作可能导致旋转轴的不断变化,而轴角表示需要不断重新计算旋转轴。

综上所述,轴角表示法是一种有用且常见的方法,用于描述三维空间中的旋转操作。它通过一个旋转轴的方向和一个旋转角度来定义旋转,可以方便地将旋转转化为旋转矩阵进行计算和应用。

旋转矩阵 欧拉角 旋转向量 四元数 详解

在计算机图形学、计算机视觉、机器人学等领域,旋转是一个重要的概念,用于描述物体在三维空间中的姿态变化。为了表示旋转,存在多种方法,包括旋转矩阵、欧拉角、旋转向量和四元数。以下是对这些方法的详细解释:

1. 旋转矩阵(Rotation Matrix):
旋转矩阵是一个3x3的矩阵,用于描述物体在三维空间中的旋转操作。矩阵的每一列和每一行都是一个单位向量,分别表示旋转后的X、Y和Z轴方向。旋转矩阵满足正交性质,即列向量和行向量都是正交归一的。旋转矩阵可以通过多种方式创建,例如使用轴角、欧拉角、四元数等。

2. 欧拉角(Euler Angles):
欧拉角是一组用于描述旋转的三个角度,通常表示为 ( \phi, \theta, \psi ) 或者 Roll、Pitch、Yaw。它们分别表示绕X轴、Y轴和Z轴旋转的角度。尽管欧拉角在某些情况下很直观,但它们存在万向节死锁问题,当某个轴的角度接近90度时,其他轴的旋转将受到限制。

3. 旋转向量(Rotation Vector):
旋转向量是一个三维向量,其方向指示旋转轴,大小表示旋转角度。旋转向量通常与轴角表示法相关联,其中向量的方向是旋转轴,向量的长度是旋转角度。旋转向量的优点之一是它在大角度旋转时较稳定。

4. 四元数(Quaternions):
四元数是一种复数扩展,用于表示旋转。它们在旋转计算中非常有用,因为它们避免了欧拉角的问题,并且在连续旋转和插值计算中表现出色。四元数由一个实部和三个虚部组成,可以使用复数运算来进行旋转计算。

每种方法都有其优点和缺点,适用于不同的应用场景。选择正确的表示方法取决于您的需求,考虑到精度、稳定性和计算效率等因素。在实际应用中,通常会根据具体情况选择最适合的旋转表示方法。

简介

  • 项目启动

    • 确定产品方向 -》需求调研,市场调研 -》业务梳理,思维导图 -》业务梳理,评审
  • 需求阶段

    • 产品原型 -》了解需求 -》 了解开发难度,评估开发工作量 -》 评估需求 -》项目里程碑,项目开发计划,项目任务分解 -》 需求概要
  • 设计阶段

    • UI界面以及标注,UI设计规范 -》 需求规格 -》 概要设计,通讯协议,表结构设计
  • 开发阶段

    • 产品开发
  • 测试阶段

    • 修改bug -》 测试用例,测试结果报告,测试周报,用户体验
  • 系统上线

    • 上线

开发流程 2

  • 软件工程的思想主要集中于加强项目管理者的工作上

  • 软件开发流程分为:

    • 可行性分析
    • 需求分析
    • 概要设计
    • 详细设计
    • 测试
    • 运维
  • 可行性分析

    • 考虑要点:技术 经济 法律 市场;
    • 说明:系统是否可以开发
    • 查看文档人员:项目经理、技术总监、客户。
  • 需求分析

    • 说明:客户和开发人员进行沟通,为开发人员开发出来软件满足客户的需要提供依据
    • 应有图:功能框架图、原型图 、用例图、功能模型图(ER图)、IPO、数据字典
    • 查看文档人员:客户、需求分析人员、开发人员、测试人员
  • 概要设计

    • 说明:开发阶段对整体框架进行设计
    • 应有图:架构图、包图、类图、接口图、流程图、功能模块对应图
    • 查看文档人员:技术总监、开发人员
  • 详细设计

    • 说明:对程序进行详细的设计
    • 应有图:时序图、协作图 、类图、活动图、状态图
    • 查看文档人员:技术总监、开发人员
  • 数据库设计

    • 说明:指导数据库设计规划以及实现;
    • 应有图:ER图、数据库关系图;
    • 查看文档人员:数据库设计人员、数据库管理员、开发人员
  • 测试情况

    • 说明:对开发好的程序进行测试,以发现系统中出现的Bug;
    • 应有图:测试用例
    • 查看文档人员:测试人员、开发人员
  • 用户手册

    • 说明:让用户快速使用这个系统,并且在使用过程中出现问题可快速解决
    • 应有图:界面截图;
    • 查看文档人员:用户,文档审核人员
  • 运行与维护

    • 说明:交付东西——目标安装程序、数据库文件、用户手册、需求报告。
    • 查看文档人员:用户、项目经理、文档审核人员
  • 小结

    • 系统要做就要有文档先行,要用文档驱动

简介

  • Tesseract库

Tesseract是什么

Tesseract是一个开源的OCR(光学字符识别)引擎,由HP实验室开发,并在2006年后由Google维护和发展。该引擎能够将图像中的文本转换成可编辑的文本格式,例如TXT、HTML或PDF。Tesseract能够处理多种语言,并且在某些情况下,它的识别准确率相当高。

Tesseract采用C++编写,但也提供了Python、Java等语言的接口,因此可以方便地在不同的编程环境中使用。它支持多种操作系统,包括Windows、Linux和macOS。

Tesseract的功能强大,应用广泛。它被用于许多领域,如文档扫描、数字化图书馆、自动化办公等。配合其他图像处理库,例如OpenCV,Tesseract能够实现更复杂的文本识别任务,并且被广泛应用于实际项目中。

Tesseract 详解

Tesseract是一个开源的OCR(光学字符识别)引擎,它能够将图像中的文本转换成可编辑的文本格式。以下是对Tesseract的详细解释:

  1. 历史

    • Tesseract最初由HP实验室开发,并于1985年首次发布。在2006年之后,Google接手了Tesseract的开发和维护,并进行了大幅改进和更新。
  2. 功能

    • 文本识别:Tesseract能够从图像中识别文本,将其转换为计算机可编辑的文本格式,例如TXT、HTML或PDF。
    • 多语言支持:Tesseract支持超过100种语言的识别,包括各种语种的拉丁字母、亚洲语言等。
    • 精度和性能:Tesseract在一些情况下具有较高的识别准确率,特别是对于印刷体文本和标准字体。
    • 配置灵活:用户可以通过配置文件来调整Tesseract的识别行为,例如指定识别语言、设置识别参数等。
  3. 使用

    • Tesseract提供了C++接口,但也支持其他编程语言的接口,如Python、Java等,因此可以方便地在不同的开发环境中使用。
    • 通常,使用Tesseract进行文本识别的过程包括图像预处理、调用Tesseract进行识别、获取识别结果并处理。
  4. 应用领域

    • 文档扫描和数字化:Tesseract常用于将扫描的文档转换为可搜索的文本,或将图书、报纸等内容数字化。
    • 自动化办公:Tesseract可以用于自动化办公流程中的文本提取和识别,如自动化填写表单、识别发票、提取邮件内容等。
    • 数据挖掘和信息检索:Tesseract也被用于数据挖掘和信息检索领域,以从图像中提取有用的信息和数据。

总的来说,Tesseract是一个功能强大且广泛应用的OCR引擎,它为用户提供了将图像中的文本转换为可编辑文本的解决方案,并在许多领域中发挥着重要作用。

简介

  • 单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。至于“单元”的大小或范围,并没有一个明确的标准,“单元”可以是一个函数、方法、类、功能模块或者子系统。
  • 单元测试通常和白盒测试联系到一起,如果单从概念上来讲两者是有区别的,不过我们通常所说的“单元测试”和“白盒测试”都认为是和代码有关系的,所以在某些语境下也通常认为这两者是同一个东西。还有一种理解方式,单元测试和白盒测试就是对开发人员所编写的代码进行测试

单元测试谁来做?

  • 单元测试一般是有开发人员或测试人员来做。谁来做并没有一个绝对的标准,要根据公司的实际情况来决定。接下来我们分析一下开发人员或测试人员做单元测试的优缺点:
  • 开发人员做单元测试:
    • 优点:开发人员对代码最熟悉,而且开发人员编程技能相对比较强,所以开发人员自己写单元测试效率上和覆盖率上都比较高
    • 缺点:开发人员平时写业务代码就要花费很多时间,有时候确实没有时间写单元测试;而且大部分开发人员没有太好的测试思想,单元测试可能只是写个最简单的用例就完了;自己写的代码自己测,往往都是不靠谱!
  • 测试人员做单元测试:
    • 优点:测试人员有比较系统的测试思想,可以更好地保证用例的覆盖。而且通过写单测测试能更好地了解具体代码结构、流程,对于后续的业务测试也非常有利。
    • 缺点:测试人员的编程技能相对比较弱,如果不同编程是无法开展单元测试的。并且测试人员对代码没有开发人员熟悉,效率会比较低。

单元测试怎么做?

  • 单元测试的实现方式包括:人工静态检查、动态执行跟踪

    • 人工静态检查:就是通常所说的“代码走读”,主要是保证代码逻辑的正确性
    • 动态执行跟踪:就是把程序代码运行起来,检查实际的运行结果和预期结果是否一致
  • 人工静态检查包含的主要内容:

    • 检查算法的逻辑正确性
    • 模块接口的正确性检查
    • 输入参数有没有作正确性检查
    • 调用其他方法接口的正确性
    • 异常错误处理
    • 保证表达式、SQL语句的正确性
    • 检查常量或全局变量使用的正确性
    • 程序风格的一致性、规范性
    • 检查代码注释是否完整
  • 动态执行跟踪

    • 动态执行跟踪需要编写测试脚本调用业务代码进行测试,为了更好的管理维护测试脚本,一般会采用单元测试框架来管理,不同的语言有不同的单元测试框架:
      • Java:JUnit、TestNG
      • Python:UintTest、pyTest
      • C++: Catch,googletest
  • 单元测试的一个重要的衡量标准就是代码覆盖率,尽量做到代码的全覆盖。常见单元测试覆盖标准:

    • 语句覆盖
    • 分支覆盖
    • 条件覆盖
    • 分支-条件覆盖
    • 条件组合覆盖
    • 路径覆盖

简介

  • vim相关的笔记

linux vim 全局替换指定字符

在 Vim 中进行全局替换指定字符的操作可以使用 :s 命令。下面是一个简单的例子:

1
:%s/old_pattern/new_pattern/g

在这个命令中,% 表示对整个文件进行操作,s/old_pattern/new_pattern/g 表示将文本中所有的 old_pattern 替换为 new_pattern。如果你希望进行大小写敏感的替换,可以在 g 后面加上 i 选项:

1
:%s/old_pattern/new_pattern/gi

如果你想确认每一次替换,可以使用 c 选项:

1
:%s/old_pattern/new_pattern/gic

在上述命令中,:s 是替换命令的缩写,old_pattern 是要被替换的字符或模式,new_pattern 是替换后的字符或模式。g 表示全局替换,i 表示大小写不敏感,c 表示逐一确认。

请根据你的需求调整命令中的参数。在 Vim 中进行全局替换时,确保你理解替换的范围和影响,以免不小心替换了不应该修改的内容。

vim 详解

Vim 是一个文本编辑器,是在 Vi 编辑器基础上发展而来的。它可以在终端中运行,并且具有很多强大的编辑功能。Vim 的强大功能主要体现在以下几个方面:

  1. 模式:Vim 有多种模式,其中最常见的是命令模式和编辑模式。在命令模式下,可以执行各种命令,比如移动光标、复制粘贴等;在编辑模式下可以编辑文本。

  2. 多窗口编辑:Vim 支持在一个屏幕内同时编辑多个文件,通过分割窗口(:sp:vsp)或分割标签页(:tabnew)来实现。

  3. 自定义:可以通过配置文件(.vimrc)来自定义 Vim 的行为,如自定义快捷键、设置颜色主题、安装插件等。

  4. 插件支持:Vim 支持各种插件,可以增强编辑功能,如代码高亮、自动补全、文件树等。

  5. 强大的编辑功能:Vim 支持各种快捷键操作,可以高效地进行文本编辑、搜索、替换等操作。

Vim 的基本使用方法包括以下几点:

  • 命令模式:按下 Esc 键进入命令模式。

    • hjkl:左、下、上、右移动光标。
    • iao:在当前光标位置插入文本。
    • x:删除光标所在处的字符。
    • dd:删除当前行。
    • yy:复制当前行。
    • p:粘贴复制或删除的文本。
    • /:进行文本搜索。
    • :w:保存文件。
    • :q:退出 Vim。
  • 编辑模式:在命令模式下按下 iao 键切换到编辑模式,进行文本编辑。

  • 插件管理:使用插件管理器(如 Vim-Plug)来安装和管理 Vim 插件。

  • 配置文件:修改 ~/.vimrc 文件来定制化 Vim 编辑器的行为。

以上只是 Vim 的基础用法,Vim 有非常丰富的功能和命令,可以根据个人需求和习惯进行更多的定制和配置。如果您想要深入学习 Vim,可以参考 Vim 的官方文档或者在线教程。

ubuntu vim-plug 安装C++插件

当您想要在 Ubuntu 上使用 Vim-Plug 安装 C++ 开发相关的插件时,您可以遵循以下步骤:

步骤 1:安装 Vim-Plug

  1. 打开终端(Ctrl + Alt + T)。
  2. 使用 curl 命令下载 Vim-Plug:
    1
    2
    curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
    https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
  3. 确保插件目录存在。如果不存在,执行以下命令创建目录:
    1
    mkdir -p ~/.vim/plugged

步骤 2:编辑 .vimrc 文件

  1. 使用 Vim 打开 .vimrc 配置文件,如果该文件不存在则创建它:
    1
    vim ~/.vimrc
  2. .vimrc 文件中添加以下内容,这会告诉 Vim 使用 Vim-Plug 管理插件:
    1
    2
    3
    4
    5
    6
    7
    8
    " Vim-Plug 设置
    call plug#begin('~/.vim/plugged')

    " 安装 C++ 相关插件
    Plug 'octol/vim-cpp-enhanced-highlight'
    " 其他插件...

    call plug#end()
    call plug#begin()call plug#end() 之间的区域是用于列出要安装的插件的地方。

步骤 3:安装插件

  1. 保存并关闭 .vimrc 文件(在 Vim 中执行 :wq)。
  2. 重新打开 Vim。
  3. 在 Vim 中输入以下命令安装列出的插件:
    1
    :PlugInstall
  4. 按下 Enter 键开始安装所列的插件。

步骤 4:配置插件

安装完成后,根据您安装的插件类型和需求,可能需要进行一些额外的配置步骤。这些步骤通常可以在每个插件的 GitHub 页面或文档中找到。

这些步骤将帮助您在 Ubuntu 上使用 Vim-Plug 安装 C++ 相关的插件,以便在 Vim 编辑器中更轻松地开发和编辑 C++ 代码。

Ubuntu vim-plug C++代码补全插件

在 Ubuntu 上,有几个流行的 Vim 插件可以用于 C++ 代码补全,其中最知名的是 YouCompleteMecoc.nvim

YouCompleteMe

YouCompleteMe 是一个功能强大的 Vim 插件,提供了高效的代码补全功能,并支持多种编程语言,包括 C++。要安装 YouCompleteMe 插件,请按照以下步骤操作:

  1. 首先,确保您已经按照上面提供的步骤安装了 Vim-Plug 插件管理器。
  2. 在您的 .vimrc 配置文件中添加 YouCompleteMe 插件:
    1
    2
    3
    4
    5
    6
    7
    8
    " Vim-Plug 设置
    call plug#begin('~/.vim/plugged')

    " 安装 YouCompleteMe 插件
    Plug 'ycm-core/YouCompleteMe', { 'do': './install.py' }
    " 其他插件...

    call plug#end()
  3. 保存并关闭 .vimrc 文件(在 Vim 中执行 :wq)。
  4. 重新打开 Vim。
  5. 在 Vim 中输入以下命令来安装 YouCompleteMe 插件:
    1
    :PlugInstall
  6. 安装完成后,进入 ~/.vim/plugged/YouCompleteMe 目录,并执行以下命令进行 YCM 插件的编译安装:
    1
    python3 install.py --clangd-completer

coc.nvim

另一个流行的 Vim 插件是 coc.nvim,它是一个具有高级特性的插件,可提供 C++ 代码补全和 IntelliSense 功能。安装步骤如下:

  1. 确保您已经按照上述步骤安装了 Vim-Plug 插件管理器。
  2. 在您的 .vimrc 配置文件中添加 coc.nvim 插件:
    1
    2
    3
    4
    5
    6
    7
    8
    " Vim-Plug 设置
    call plug#begin('~/.vim/plugged')

    " 安装 coc.nvim 插件
    Plug 'neoclide/coc.nvim', {'branch': 'release'}
    " 其他插件...

    call plug#end()
  3. 保存并关闭 .vimrc 文件(在 Vim 中执行 :wq)。
  4. 重新打开 Vim。
  5. 在 Vim 中输入以下命令安装 coc.nvim 插件:
    1
    :PlugInstall
  6. 安装完成后,在 Vim 中使用 :CocInstall coc-clangd 安装 C++ 相关的语言服务器。

安装完成后,您可以根据需要配置这些插件以满足您的需求,并享受更加便捷的 C++ 开发体验。

vim 删除指定插件

要从 Vim 中删除插件,你需要编辑你的 .vimrc 文件,找到包含你想删除插件的行,并将其删除。然后保存文件并退出 Vim。

假设你正在使用 Vim-Plug 来管理你的插件,你可以按照以下步骤来删除一个插件:

  1. 打开终端并输入以下命令以编辑你的 .vimrc 文件:

    1
    vim ~/.vimrc
  2. 找到你想要删除的插件的配置行。它们通常具有 Plug 字样。比如:

    1
    Plug 'some-plugin'
  3. 将你想要删除的插件的配置行从 .vimrc 文件中删除。

  4. 保存并关闭文件。你可以按下 Esc 键,然后输入 :wq 并按回车键保存并退出。

  5. 重新打开 Vim,然后执行 :PlugClean 命令,它会删除未在 .vimrc 文件中列出的任何插件。

这样就完成了删除插件的操作。请记住,这些步骤可能因你的插件管理器或特定的插件而有所不同,因此你需要根据你自己的情况进行调整。

Vim-plug

安装

用法

  • 安装插件
    • 要安装插件,你必须如下所示首先在 Vim 配置文件中声明它们。一般 Vim 的配置文件是 ~/.vimrc
    • 请记住,当你在配置文件中声明插件时,列表应该以 call plug#begin(PLUGIN_DIRECTORY) 开始,并以 plug#end() 结束。
    • 例如,我们安装 “lightline.vim” 插件。为此,请在 ~/.vimrc 的顶部添加以下行。
      1
      2
      3
      call plug#begin('~/.vim/plugged')
      Plug 'itchyny/lightline.vim'
      call plug#end()

检查状态

  • 使用以下命令检查状态:
    • :PlugStatus

安装插件

  • 使用以下命令安装:
    • :PlugInstall

更新插件

  • 要更新插件,请运行:
    • :PlugUpdate
  • 更新插件后,按下 d 查看更改。或者,你可以之后输入 :PlugDiff。

审查插件

  • 有时,更新的插件可能有新的 bug 或无法正常工作。要解决这个问题,你可以简单地回滚有问题的插件。输入 :PlugDiff 命令,然后按回车键查看上次 :PlugUpdate的更改,并在每个段落上按 X 将每个插件回滚到更新前的前一个状态。

删除插件

  • 删除一个插件删除或注释掉你以前在你的 vim 配置文件中添加的 plug 命令。然后,运行 :source ~/.vimrc 或重启 Vim 编辑器。最后,运行以下命令卸载插件:
    • :PlugClean
  • 该命令将删除 vim 配置文件中所有未声明的插件。

升级 Vim-plug

  • 要升级vim-plug本身,请输入:
    • :PlugUpgrade

NERDTree

  • 这个插件是几乎所有研发人员都会安装的一个插件——目录树,可以支持在不退出vim的编辑器的前提下,在文件中快速切换,同时能让开发人员快速掌握项目目录结构,是提升开发效率必不可少的工具

  • 安装

    1
    2
    3
    call plug#begin()
    Plug 'preservim/nerdtree'
    call plug#end()
  • 配置

    • NERDTree默认无须配置即可直接使用,当然更改部分映射后,可以使得目录树试用起来更加得心应手。最常见的配置在~/.vimrc添加如下命令,即可使用Ctrl+n快速开启目录树。
      1
      map <C-n> :NERDTreeToggle<CR>
  • 使用

    • 目录树的使用主要通过在vim的command模式下键入如下命令,即可达到相应的效果。
    • ?: 快速帮助文档
    • o: 打开一个目录或者打开文件,创建的是 buffer,也可以用来打开书签
    • go: 打开一个文件,但是光标仍然留在 NERDTree,创建的是 buffer
    • t: 打开一个文件,创建的是Tab,对书签同样生效
    • T: 打开一个文件,但是光标仍然留在 NERDTree,创建的是 Tab,对书签同样生效
    • i: 水平分割创建文件的窗口,创建的是 buffer
    • gi: 水平分割创建文件的窗口,但是光标仍然留在 NERDTree
    • s: 垂直分割创建文件的窗口,创建的是 buffer
    • gs: 和 gi,go 类似
    • x: 收起当前打开的目录
    • X: 收起所有打开的目录
    • e: 以文件管理的方式打开选中的目录
    • D: 删除书签

简介

  • WPA是WiFi Protected Access的缩写,中文含义为“WiFi网络安全存取”。WPA是一种基于标准的可互操作的WLAN安全性增强解决方案,可大大增强现有以及未来无线局域网络的数据保护和访问控制水平

  • 经过编译后 的 wpa_supplicant源程序可以看到两个主要的可执行工具:wpa_supplicant 和 wpa_cli。wpa_supplicant是核心程序,它和wpa_cli的关系就是服务和客户端的关系:后台运行wpa_supplicant,使用 wpa_cli来搜索、设置、和连接网络

  • wpa_supplicant.conf文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ctrl_interface=/sbin/wpa_supplicant       //wpa_supplicant命令执行文件目录
    ap_scan=1

    network={
    ssid="GH_wx_05" //WiFi 名字
    psk="Grand@honor666666!@#" //WiFi 密码
    key_mgmt=WPA-PSK //加密方式
    # key_mgmt=NONE //不加密
    }
  • 开启wifi服务:wpa_supplicant -B -i wlan0 -c /data/cfg/wpa_supplicant.conf

  • 重新读取上述配置:wpa_cli reconfigure

  • 并重新连接:wpa_cli reconnect

简介

  • WPS 使用笔记

wps word一键删除空行

  • 第一步:选择WPS-Word文档中的“开始”菜单栏,选择旗下的“文字工具”。 继续点击“删除”,此时会跳出四个选项,如下图所示,Sara点击的是“删除空段”。
  • 第二步:点击“删除空段”后,所有的Word文档空白行就一秒全部消失啦。

wps 分页

WPS Office(金山办公)是一款办公软件套件,包括文字处理、演示文稿和电子表格等功能。在WPS文字(WPS Writer)中,你可以设置分页选项来控制文档的分页方式。以下是如何在WPS文字中进行分页设置的一般步骤:

  1. 打开文档: 打开你想要进行分页设置的文档。

  2. 选择页面布局: 在菜单栏中选择“页面布局”选项,通常位于顶部导航栏的位置。

  3. 设置页面大小: 在页面布局选项中,你可以选择预定义的页面大小,如A4、信纸等,或者自定义页面大小。选择适合你需要的页面大小。

  4. 设置页面边距: 同样在页面布局选项中,你可以设置页面的上、下、左、右边距。这些边距会影响页面内容的位置和间距。

  5. 设置分页方式: 在页面布局选项中,你可以设置文档的分页方式。有两种常见的分页方式:

    • 分页符: 你可以手动插入分页符来控制文档的分页。在需要分页的位置插入分页符,文档将在此处分页。
    • 自动分页: 选择此选项后,WPS会根据页面大小、字体大小等因素自动进行分页,无需手动插入分页符。
  6. 插入分节符(可选): 如果你的文档需要不同的分页设置,比如首页不显示页眉页脚,你可以在“插入”菜单中选择“分节符”来实现这些设置。

  7. 预览分页效果: 在设置完分页选项后,你可以通过查看打印预览来检查分页效果。这可以帮助你确认文档在打印或显示时的分页情况。

  8. 保存文档: 确认分页设置无误后,记得保存文档以保存你的分页设置。

请注意,WPS Office的界面可能在不同的版本中略有不同,但一般来说,上述步骤适用于大多数版本的WPS文字。如果你使用的是特定版本,可以参考软件自带的帮助文档或在线资源,以获取更详细和准确的分页设置指导。

wps 怎么插入分页符

在WPS Office文字处理软件(WPS Writer)中,插入分页符是很简单的。分页符会将文档内容分为两部分,使得在分页符之前的内容位于前一页,分页符之后的内容位于下一页。以下是在WPS Writer中插入分页符的步骤:

  1. 打开你要编辑的文档,确保你在编辑模式下。

  2. 将光标移动到你想要插入分页符的位置。这通常是你希望在这里开始新的一页的地方。

  3. 在菜单栏中,点击”插入”选项。

  4. 在弹出的下拉菜单中,选择”分页符”选项。这将在你的光标所在位置插入一个分页符。

  5. 保存你的文档以保存分页符的插入。

现在,你已经成功地在WPS Writer中插入了一个分页符。在此分页符之前的内容将出现在前一页,分页符之后的内容将出现在下一页。

请注意,分页符只会影响打印或显示时的页面分割,而不会在编辑模式下直接显示分页符图标。如果你希望在编辑模式下看到分页符的位置,可以在WPS Writer的“查看”选项中启用“非打印字符”或类似的选项,这样你就可以看到分页符的位置。

以上是在WPS Writer中插入分页符的一般步骤,实际界面可能会根据不同的WPS Office版本略有不同。如果你使用的是特定版本,可以查阅该版本的帮助文档或在线资源以获取更详细和准确的插入分页符的指导。

简介

计算机系统 – 基础知识

  • 计算系统,是一个完整的工作系统。系统不仅包括计算机,还包括各种软件以及外部设备。

  • 计算机就是用于执行指定操作的机器,这些操作通常是一组指令的集合,这些指令也称为软件(software)

  • 计算机硬件(hardware)是系统的物理组成部分,是可以真真切切触摸到的

  • 硬件包括计算机及其周边设备,例如键盘,鼠标,显示器,硬盘,打印机等

  • 计算机软件是以电子形式在硬件中驻留和运行的程序,例如编译器,操作系统以及应用程序等。软件提供了人机接口(Human Computer Interface, HCI),并定义了计算机应该执行的操作

计算机硬件

  • 在冯·诺依曼的模型里,可以看到输入设备,输出设备,存储单元以及由控制单元(control unit)和带有累加器(accumulator)的算数逻辑单元(Arithmetic Logic Unit, ALU)构成的模块

  • 存储单元存储数据,控制单元则控制数据的传输和数据的处理。

  • 控制单元取回指令并对其进行译码后存入存储单元中,同时从输入设备接收数据,并将数据存入存储单元

  • 控制单元对可执行指令进行译码,并将数据送入ALU。 ALU执行操作,控制单元则将计算结果送入输出设备。

  • 这里的控制单元和ALU一起称为中央处理单元(Central Processing Unit, CPU)

  • ALU中的累加器是一组高速寄存器的集合,用作算术和逻辑操作的操作数和结果的临时存储

  • ALU中的寄存器大小对应着计算机的字长(word size)。

  • 一般的字长有16位,32位,64位,这取决于处理器的设计方案

  • 1位代表一个二进制位,而且处理器的字长都是2的幂

计算机软件

  • 计算机软甲包含了我们希望计算机执行的指令或者命令。

  • 在计算机软件中的分类中有几类比较重要,包括操作系统,软件工具,各种程序语言的编译器

  • 如果某个工程问题可以通过使用软件工具解决,通常来说,这比写一个程序来解决问题更高效。

  • 然而,很多问题都不能通过现有软件工具来解决,或者软件工具在需要解决问题的计算机系统上不可用,因此,我们也需要知道如何使用计算机语言来写程序。

  • 随着一些功能强大的软件的出现,这些软件除了支持专门的操作系统还包含了编程语言,这使得软件工具和计算机语言之间的区别变得越来越模糊

计算机语言

  • 计算机语言有不同的层次

  • 机器语言(machine language)是最基础的语言,是与计算机硬件设计密切相关的

  • 因为计算机的设计是建立在二态技术(类似的情况有电路的开合,开关的打开与关闭,电池的正负极)基础上的,所以机器语言也使用两种符号来编写,通常使用数字0和1来表示。

  • 因此,机器语言也是一种二进制语言,它的指令都是使用由0和1组成的序列携程的,这些序列称为二进制串

  • 因为机器语言是与计算机硬件紧密相关的,所以SUN计算机上与HP计算机上的机器语言是不同的

  • 对于某种特定的计算机设计语言,汇编语言(assembly language)也是唯一的,但是汇编语言的指令是用可读性更好的符号语句而非二进制串编写的

  • 汇编语言的语句类型通常并不是很多,在使用汇编语言时,必须了解与之相应的硬件信息,

  • 包含微处理器的设备通常要求程序能够极快地执行,这样的程序称为实时程序(real-time program)

  • 实时程序通常使用汇编语言编写,这样可以发挥特定计算机硬件的优势,以提高执行速度

  • 高级语言(high-level language)是具有类似自然语言的命令和指令的计算机语言,C++,C, Fortran,Ada, Java,Basic等都是高级语言

  • 执行计算机程序,要执行使用诸如C++这样的高级语言编写的程序,必须先将高级语言指令翻译成机器语言。

  • 执行这种翻译任务的程序称为编译器(compiler)

  • 在编译阶段出现的错误称作解析错误(parse error)或语法错误(syntax error)

  • 当没有语法错误后,编译器就可以成功地翻译程序,并声称机器语言形式的程序,生成的程序将完成最开始C++程序所要执行的功能。

    • 这一,C++程序称为源文件(source file),而生成的机器语言版本则称为目标文件(object file)
    • 因此,源程序和目标程序所描述的功能是一致的,但是源程序使用高级语言编写的,而目标程序则是以机器语言的形式
  • 执行(execution),这些步骤包括将目标程序与机器语言语句进行链接(linking)和把程序载入(loading)内存

  • 在执行阶段出现的错误称为执行错误(execution error),运行时错误(run-time error)或逻辑错误(logic error),这些错误也叫做程序bug

  • 如果执行错误是由于程序中所编写的语句产生的,必须在源程序中修改错误并重新进行编译,这个过程叫做调试(debugging)

数据的表示与存储

  • 在数字计算机中,一个二进制位可以使用一个位(bit)表示。

  • 位上的值在任何时候都只能是0或1.从硬件的角度来说,当该位处于关闭或低电位时,它的值为0,而当其处于打开或高电位时,其值为1

  • 二进制数在内存中以序列的形式存储,位序列称为字(word)

  • 字的长度每增加1位,字所表示的数的大小就以2的幂增加,而其所能表示的范围就翻一倍

  • 内存中可用的字的数目称为内存空间,或者地址空间(address space)

  • 字长决定了存储在某个地址中的数值范围,而地址空间则决定了可以存储多少个字

  • C++包含整型数,浮点数,字符和布尔值等内建的数据类型。每种数据类型都由一个以字节(byte)为单位来确定的预定义大小,1个字节就是一个8位的序列。

  • 为了定义标识符(identifier)并为它分配空间,则需要使用类型声明语句(type declaration statement)。

  • 当定义一个标识符时,便确定了其数据类型,并在内存中分配相应字节数的空间。

  • 当数据存储在内存中时,它是以位序列存在的。

  • 这些位序列可能是指令,数字,字符,图像或数字信号的一部分,或者是其他类型的数据

    • 负数的存储
    • 浮点数的存储

框架(Framework)

  • 什么是框架?

    • 框架(Framework)是构成一类特定软件可复用设计的一组相互协作的类。框架规定了你的应用的体系结构。
    • 它定义了整体结构,类和对象的分割,各部分的主要责任,类和对象怎么协作,以及控制流程。框架预定义了这些设计参数,以便于应用设计者或实现者能集中精力于应用本身的特定细节
    • 框架一般处在低层应用平台和高层业务逻辑之间的中间层
  • 为什么要用框架?

    • 因为软件系统发展到今天已经很复杂了,特别是服务器端软件,涉及到的知识,内容,问题太多。在某些方面使用别人成熟的框架,就相当于让别人帮你完成一些基础工作,你只需要集中精力完成系统的业务逻辑设计。
    • 而且框架一般是成熟,稳健的,他可以处理系统很多细节问题,比如,事务处理,安全性,数据流控制等问题。
    • 还有框架一般都经过很多人使用,所以结构很好,所以扩展性也很好,而且它是不断升级的,你可以直接享受别人升级代码带来的好处
  • 软件为什么要分层?

  • 为了实现“高内聚、低耦合”。把问题划分开来各个解决,易于控制,易于延展,易于分配资源等
  • 框架和设计模式

    • 构件通常是代码重用,而设计模式是设计重用,框架则介于两者之间,部分代码重用,部分设计重用,有时分析也可重用
    • 框架与设计模式虽然相似,但却有着根本的不同。设计模式是对在某种环境中反复出现的问题以及解决该问题的方案的描述,它比框架更抽象
    • 框架可以用代码表示,也能直接执行或复用,而对模式而言只有实例才能用代码表示;
    • 设计模式是比框架更小的元素,一个框架中往往含有一个或多个设计模式,框架总是针对某一特定应用领域,但同一模式却可适用于各种应用
  • 构件(component)

    • 构件是面向软件体系架构的可复用软件模块。
    • 构件是可复用的软件组成成份,可被用来构造其他软件。它可以是被封装的对象类、类树、一些功能模块、软件框架(framework)、软件构架(或体系结构Architectural)、文档、分析件、设计模式(Pattern)等
    • 1995年,Ian Graham给出的构件定义如下:构件(Component)是指一个对象(接口规范、或二进制代码),它被用于复用,接口被明确定义
    • 构件是作为一个逻辑紧密的程序代码包的形式出现的,有着良好的接口
    • 采用构件软件不需要重新编译,也不需要源代码并且不局限于某一种编程语言。该过程叫做二进制复用(Binary Reuse),因为它是建立在接口而不是源代码级别的复用之上的。虽然软件构件必须遵守一致的接口,但是它们的内部实现是完全自动的。因此,可以用过程语言和面向对象语言创建构件
  • 构件和面向对象设计的差别

    • 在纯面向对象的设计中,对象(类)、封装和继承三者缺一不可,但对构件可以没有继承性,只要实现封装即可
    • 从构件和对象的生成方式上,对象生成属于实例化的过程,比较单一,而生成构件的方式较多
    • 构件是设计的概念,与具体编程语言无关,不像对象属于编程中的概念,要依赖于具体的编程语言
    • 在对构件操作时不允许直接操作构件中的数据,数据真正被封装了。而对象的操作通过公共接口部分,这样数据是可能被访问操作的
    • 对象对软件复用是通过继承实现的,构件对软件复用不仅可以通过继承还可以通过组装时的引用来实现
    • 因此,构件不是对象,只是与对象类似
  • 在软件生产中有三种级别的重用:

    • 内部重用,即在同一应用中能公共使用的抽象块
    • 代码重用,即将通用模块组合成库或工具集,以便在多个应用和领域都能使用
    • 应用框架的重用,即为专用领域提供通用的或现成的基础结构,以获得最高级别的重用性
  • 框架开发

    • 框架的最大好处就是重用。面向对象系统获得的最大的复用方式就是框架,一个大的应用系统往往可能由多层互相协作的框架组成
    • 由于框架能重用代码,因此从一已有构件库中建立应用变得非常容易,因为构件都采用框架统一定义的接口,从而使构件间的通信简单
  • 框架解决的问题

    • 框架要解决的最重要的一个问题是技术整合的问题
    • 软件企业的研发将集中在应用的设计上,而不是具体的技术实现,技术实现是应用的底层支撑,它不应该直接对应用产生影响
    • 举例:
      • 一个做视频流应用的软件企业,他为电广行业提供整体的解决方案。他的优势在于将各种各样的视频硬件、服务器、和管理结合起来,因此他扮演的是一个集成商的角色。因此他的核心价值在于使用软件技术将不同的硬件整合起来,并在硬件的整合层面上提供一个统一的管理平台。所以他的精力应该放在解决两个问题
        • 如何找到一种方法,将不同的硬件整合起来,注意,这里的整合并不是技术整合,而是一种思路上的整合
        • 如何描述这个管理系统的规范。你需要描述各种管理活动,以及管理中所涉及的不同实体。因为管理系统是针对硬件的管理,所以它是构架在硬件整合平台之上的

数据模型(Data Model)

  • 数据模型(Data Model)是数据特征的抽象,它从抽象层次上描述了系统的静态特征、动态行为和约束条件,为数据库系统的信息表示与操作提供一个抽象的框架。数据模型所描述的内容有三部分,分别是数据结构、数据操作和数据约束

  • 模型可更形象、直观地揭示事物的本质特征,使人们对事物有一个更加全面、深入的认识,从而可以帮助人们更好地解决问题。利用模型对事物进行描述是人们在认识和改造世界过程中广泛采用的一种方法。计算机不能直接处理现实世界中的客观事物,而数据库系统正是使用计算机技术对客观事物进行管理,因此就需要对客观事物进行抽象、模拟,以建立适合于数据库系统进行管理的数据模型。数据模型是对现实世界数据特征的模拟和抽象

  • 数据模型是数据库设计中用来对现实世界进行抽象的工具,是数据库中用于提供信息表示和操作手段的形式构架。数据模型是数据库系统的核心和基础

  • 数据模型所描述的内容包括三个部分:数据结构、数据操作、数据约束

    • 数据结构:数据模型中的数据结构主要描述数据的类型、内容、性质以及数据间的联系等。数据结构是数据模型的基础,数据操作和约束都建立在数据结构上。不同的数据结构具有不同的操作和约束
    • 数据操作:数据模型中数据操作主要描述在相应的数据结构上的操作类型和操作方式
    • 数据约束:数据模型中的数据约束主要描述数据结构内数据间的语法、词义联系、它们之间的制约和依存关系,以及数据动态变化的规则,以保证数据的正确、有效和相容

如何分析和解决一个任务:思维方式

  1. 先从整体上有一个总体思路,比如各个模块之间如何通信、依赖等,然后从一个点开始,照着调用路径分析下去,不要看一个类中的每个方法,而是只看用到的方法。
  2. 把所想要完成的目标分步实现,如果思路不清晰,不知道如何去做,可以模拟现实中的步骤。
    1. 要把想实现的东西转换成代码,不要想着最终结果好难,不知道怎么做。
    2. 先分步,一步一步完成,然后分别去想每一步是怎么实现的。第一次写完之后肯定是缺陷的,仔细反复调试,慢慢修改优化,不要看着目标就被吓到。
  3. 函数最主要的作用就是将一个大型程序分解成多个易于管理的小部分,这一过程称为分解(decomposition)。而你所需做的应是将一个高层次问题细分为一系列低层次的函数,每一个函数有其自己独立的功能。然而,找到问题正确的细分方法有很大的挑战,需要不断练习、思考和尝试。编程是一门艺术,好的问题分解策略主要来源于实际经验。
  4. 然而,作为一种通用的规则,问题的分解过程一般从程序的主程序开始。此时,我们将整个程序视为一个整体,并尝试从中分析并抓取出其主要部分。一旦程序的最主要部分被识别出来,就可以将它们定义为一些相互独立的函数。由于某些函数可能本身依然复杂,因此通常需要将他们再分解为更小的部分。我们可以不断重复这一分解过程直到每个问题足够简单明了以便于解决。上述分解过程称为自顶向下的程序设计(top-down design)逐步求精的方法(ste[wose refinement)

深入理解计算机操作系统

过程是软件中一种很重要的抽象

  • 它提供了一种封装代码的方式,用一组指定的参数和一个可选的返回值实现了某种功能.然后,可以再程序中不同的地方调用这个函数,设计良好的软件用过程作为抽象机制,隐藏某个行为的具体实现,同时又提供清晰简洁的接口定义,说明要计算的是哪些值,过程会对程序状态产生什么样的影响.
  • 不同编程语言中,过程的形式多样:函数(function),方法(method),子例程(subroutine),处理函数(handle)等等

数据对齐

  • 许多计算机系统对基本数据类型的合法地址做出了一些限制,要求某种类型对象的地址必须是某个值K(通常是2,4或8)的倍数,这种对齐限制简化了形成处理器和内存系统之间接口的硬件设计
  • 强制对齐:
    • 对于大多数x86-64指令来说,保持数据对其能够提高效率,但是它不会影响程序的行为
    • 另一方面,如果数据没有对齐,某些型号的Intel和AMD处理器对于有些实现多媒体操作的SSE指令,就无法正确执行.

理解指针

  • 指针以一种统一方式,对不同数据结构中的元素产生引用

  • 每个指针都对应一个类型,这个类型表明该指针指向的是哪一类对象

    • int* ip表示变量ip是一个指向int类型对象的指针,char** cpp表示cpp指针指向的对象自身就是一个指向char类型对象的指针
    • 通常,如果对象类型为T,那么指针的类型为T*;特殊的, void *类型代表通用指针.比如说,malloc函数返回一个通用指针,然后通过显式强制类型转换或者赋值操作那样的隐式强制类型转换,将它转换成一个有类型的指针.
    • 指针类型不是机器代码中的一部分,它们是C语言提供的一种抽象,帮助程序员避免寻址错误
    • 每个指针都有一个值,这个值是某个指定类型的对象的地址.特殊的NULL(0)值表示该指针没有指向任何地方
    • 指针用&运算符创建.这个运算符可以应用到任何lvalue类的C表达式上,lvalue表示可以出现在赋值语句左边的表达式
    • *操作符用于间接引用指针,其结果是一个值,它的类型与该指针的类型一致,间接引用是用内存引用来实现的,要么是存储到一个指定的地址,要么是从指定的地址读取
    • 数组与指针紧密联系.一个数组的名字可以像一个指针变量一样引用(但是不能修改).数组引用(例如a[3])与指针运算和间接引用(例如*(a + 3))有一样的效果.数组引用和指针运算都需要用对象大小对偏移量进行伸缩
    • 将指针从一种类型强制转换成另一种类型,只改变它的类型,而不改变它的值.强制类型转换的一个效果是改变指针运算的伸缩
    • 指针也可以指向函数.这提供了一个很强大的存储和向代码传递引用的功能,这些引用可以被程序的某个其他部分调用
  • 内存越界引用和缓冲区溢出

    1. 模型相关的,b站视频
    2. 多看项目(github),多练
    3. 大厂的代码,main中变量的声明(amlogic, nvidia)
    4. shell 不必花费太多精力,推荐:python,php(现在不要去学,单点击穿,现在主要学习C++)

如何阅读大型项目的代码?

  • 目的性:读代码的时候如果有目的性是最好的。
  • 时间:总体来讲,阅读大型项目的代码需要时间。
  • 方法论:抽象地说,阅读代码有两种方向,自底向上和自顶向下。
    • 自底向上,从具体的文件到子模块,从子模块到功能集,再到整个项目,强调的是从具体实现出发总结出一般抽象。
    • 自顶向下,从项目的顶层设计到责任分发,从责任分发到功能分发,再到具体的实现代码,强调的是从抽象设计出发落实到具体实现。
    • 两种方法是两个不同的视角。实践中经常需要结合两种方向随时切换地采用,当对大方向了解不足的时候自顶向下的看,当对实现细节不够明确的时候自底向上的看

上下文 context

  • 维基百科

    • 在计算机科学中,任务(task)的上下文(context)是一个任务所必不可少的一组数据(该任务可以是进程,线程)。
    • 这些数据允许任务中断,在这之后仍可在同一个地方继续执行。上下文的这一概念在中断的任务的场景下具有重大意义。其中,任务在被中断之后,处理器保存上下文并提供中断处理(interrupt service routine)。因此,上下文越小,延迟越小。
    • 上下文的数据可能存放于处理器寄存器,任务所利用的内存,某些操作系统管理的任务所使用的控制寄存器(control registers)
  • 通俗的理解,上下文,也就是执行任务所需要的相关信息。

  • 这个任务可以是一段代码,一个线程,一个进程,一个函数。当这个“任务”相关的信息需要保存下来时,就可以使用context来记录。

关于业务对象(Business Object)本质的思考

  • 对于采用OO(Object Oriented)思想,并具有N层架构的计算机程序而言,业务对象(Business Object)一般位于业务逻辑层(也叫领域层[1]),作为领域模型元素的一部分,描述了来自于业务域中的一个人、事、物或概念[2],主要用来解决商业逻辑(即业务操作)问题,是为实现当前软件(或系统)的某一(或某些)特定功能而服务的。因此,它仅仅是从当前业务域的角度,对现实世界的一次抽象。

  • 业务对象、业务实体、实体、领域对象在某种程度上是可以互换的术语[此处仅仅说是“某种程度上”,目的在于分析BO三要素的实质,针对于不同的理论,这几个名词确实存在差别]

  • 对象三要素

    • 标识(identity),是唯一区别其他对象的标志;
    • 状态(state),描述对象所蕴含的信息;
    • 行为(behavior),对象所持有的、描述对象如何被使用的方法

状态

  • 相对于字段、变量、属性等词,用“状态”一词来描述对象的“性格特点”最为合适。字段、变量、属性等,无非是描述对象状态的不同表现手法

  • 就目前个人对BO状态的理解而言,BO的状态信息有两类:固有信息和动态信息。

    • 固有信息,是对象从诞生时与生俱来的信息(就像一个新生命的诞生一样,出生年月日、肤色、性别等信息是生来就有的);
    • 动态信息,即随着BO的成长,它会走入某一个人生场景中,扮演了某一个角色,从而在这个场景中被赋予了一些额外的信息,如:小明是个学生(从入学时,学生的基本信息被赋予),某天他去市图书馆借阅图书,此时他在借书这个场景中扮演了借书者这个角色,从而具有了借阅证、借阅信息等动态信息。
  • 固有信息

    • 业务对象在被构建(初始化)后,应达到一个相对比较稳定,且具有一定业务含义的状态,即业务对象的属性应已进行了相应的初始化设置,这样的构建才算合理、完整
    • 与人类世界类似,人在出生时,就已经构造好了婴儿的鼻子、眼睛、手等内容,虽然此时他还没有衣服、母语、身份证等信息,但他在出生时,是一个相对较稳定且有意义的个体,就可以完成婴儿的核心操作,如:哭、呼吸、挥手等。
    • 提前构造好该构造好的信息(注意:不是所有的信息都要一股脑的全构造好)是保证BO不被滥用的第一步
  • 动态信息

    • 进入某一场景,扮演某一角色(我更喜欢用“戴上帽子”这个说法),将拥有额外的动态属性。同“固有属性”的构建,某一业务对象走入特定的场景,扮演了另一角色时,也应该将这些动态属性予以设置
    • 对象应尽量在构建自身的过程中完成自身状态的设置

属性封装

  • 在OO的世界里,封装的概念是最简单的,但却是最关键且最难以把握的

  • 信息不封装(或封装不完整)带来的副作用

    • 内聚,难。业务对象的信息过多的暴露出去,容易滋生强盗逻辑,想捏回去形成一团,难!信息全部都暴露给外界,调用者还需要你BO干嘛?原因很简单:我能够伸手拿到你的任何信息,想实现什么就实现什么,可以为所欲为。如果你还有胆量暴露一些更改BO属性的权限,那我岂不是想怎么改就怎么改
    • 解耦,难。一个成语叫“覆水难收”,放出去的信息将被调用者肆意使用,而且呈现出快速蔓延的趋势,一张复杂的耦合网必然产生。等回头开始重构解耦时,发现堆积如山的代码、耦合似网的结构,已经让你无从下手。动一下,就引起全身阵痛
    • 常见的做法
      • 刨一小块,改改变量名、方法名,移一些代码,用接口再包装一下(隔离嘛),循环的修改,最终发现进展依然是非常缓慢,几乎还没触及到业务核心;
      • 先用方法(1)试试,一阵子后,MD,烦死了,直接推倒重新搞。这些做法还需要考虑一个问题:放出去的接口和信息已被调用者大量使用,怎么办?
  • 针对上述的苦痛,推荐下面的做法:

    • 在对象构建时,把能设置的状态信息尽可能的予以赋值,提前封装;
    • 尽可能的不要公布内部信息。能够private的,尽可能的私有。除非迫不得已,尽量不要将setter() 放出,仅使其read only

行为

  • 业务行为才是软件真正所关注的问题,对象的行为方式是对象价值的重要体现,也是区别于其他对象的重要标志。

  • 因此,我们说“BO因职责而存在!”

  • 贫血VS充血

    • 贫血对象
      • 由不具有任何行为的业务对象形成的领域模型,称为“贫血模型”[2]。对只有属性的getter/setter方法,不具有业务行为的BO,可认为是“贫血对象”。
      • 丧失业务逻辑行为的贫血对象,和Value Oject类似,扮演了Data Container的角色,而在业务域中的逻辑操作方面将失去能力(或被遗弃、边缘化)
    • 充血对象
    • 按大师的说法,与BO直接相关的行为职责将划归到BO中,使其在领域模型中扮演重要的角色
  • 但是二者不能绝对的说谁好、谁不好,应该一分为二的去看,它们各自具有其特点,应用在不同的场景中。特别地,对于那些需求难以完全吃透、明确,或许用贫血模型较充血模型要更好把控局势。

  • 用户需求——业务——领域是一个对知识掌握程度递增的过程,领域模型的建立应基于对客观业务域的透彻掌握,不能偏左,也不可以偏右(不就是博弈么?没有最优秀的东西,只存在考虑诸多因素下的较为合适的东西)

  • business core

    • 它应该是最精炼、纯粹、简单、直接、轻量级的业务核心。
    • 因此,不属于核心业务逻辑范畴的职责和行为(如:持久化操作),尽量抛出去交给该处理它们的对象去处理。
  • 上帝类(God class)

    • 可以认为它就是一个充血充得快爆掉的对象
    • 它几乎可以干所有涉及到它的工作,从而形成代码有几百行乃至上千行的牛X类
    • 有了这么一个牛X类,其他类不就成了浮云和鸡肋了么?这样可能引发很多问题
      • 理解难。几千行的代码,没有几个人有耐心阅读,几乎没人能够完全理解其表达的业务含义。
      • 修改难。没有很好的理解,如何修改?如何重构?
      • 扩展难。丢了它玩不转,不丢它又引来一堆麻烦,对于一个几千行的实现类来说(除非大多都是public static 的方法),吃资源不说,接口隔离、应对扩展方面也是比较吃力的。
  • 谁拥有数据,谁持有行为

    • BO行为的本质是对BO自身状态的改变,以实现业务目标,并且这种状态的更改可能还需要其他协作者的参与(关联关系)。
    • 因此,我们可以说“谁拥有数据,谁就持有更改这些数据(状态)的行为
    • 现实中,跟BO有关系的行为可能较多,全部纳入到BO中,会造成BO的臃肿和污染,违背SRP(职责单一)
      • 可重用度高或是对象固有、与BO状态密切关联的方法放在BO中
      • 可重用度低或者不是对象所固有(而依赖于特定场景)、与BO状态没有密切联系的方法放在BO管理者或服务层
  • 方法属于客户

    • BO就是一个黑盒子,其中包含了逻辑和数据,而对象的使用者不知道里面有什么数据,也不知道实际的运行逻辑。使用者所能做的就是与对象进行交互,以完成当前的业务目标。因此,对象的行为是为客户而定
    • 行为(方法、职责)是BO存在的根本,而行为就是为了交互,为供调用者所使用。
    • 调用者会根据自己的需要,向它认为应该由谁提供行为的BO发出操作申请,一切都是以“客户(调用者)”为中心而服务的

软件工程

  • 程序 = 算法 + 模型 + 数据结构

  • 传统的程序只是算法和数据结构的组合,但是在AI迅猛发展的今天,在程序里几乎都有个“模型”

  • 模型,一般是指机器学习或深度学习训练出来的Model,里面既有逻辑又有数据,所以它既不是单纯的算法,也不是单纯的数据结构。

  • 软件工程师 = 程序员 + 软件工程知识

  • PM(Program Manager) = 项目管理 + 产品管理,直译为程序经理,实际上是项目管理和产品管理的二合一角色

  • 团队 = PM + 软件工程师 + Designer

    • Designer, 直译就是设计师,负责用户界面和交互的设计
    • 通常情况下,PM和软件工程师是长期合作的,而Designer有自己的独立组织,与团队是临时合作
  • 软件工程 = 团队 + 过程定义 + 执行

  • 软件 = 程序 + 软件工程

  • 软件公司 = 软件产品 + 商业模式

商业模式的三个概念:产品, 项目, 服务

  • 产品,其特点由公司决定要做什么,给客户提供什么,具有长期规划,不断迭代

  • 项目,包括两类:

    • 一种是狭义的,在销售给客户产品后,再同时开发/提供一些定制软件,那么会有配套的开发人员进行售后服务
    • 另一种是广义的,其宿主是服务或产品,完成其一个小功能
  • 服务,以云端服务为主,具有战略意义,这种服务的后台通常有超级复杂的架构体系支撑,在性能,可用性,可靠性上下足了功夫,高并发大容量

简介

  • CNPY第三方工具相关笔记

cnpy 是什么

cnpy 是一个用于读取和写入.npy(NumPy数组文件)的C++库。这个库使C++程序能够方便地处理NumPy数组数据,而无需依赖Python。NumPy是一个Python库,用于处理多维数组和科学计算,但有时需要在C++应用程序中使用NumPy数组数据。cnpy库提供了在C++中处理.npy文件的功能,包括读取和写入NumPy数组。

以下是cnpy库的一些主要特点和功能:

  1. 读取.npy文件cnpy库允许C++程序读取.npy文件中的NumPy数组数据,并将其转换为C++数据结构,以便在C++中进行进一步处理和分析。

  2. 写入.npy文件:使用cnpy库,C++程序可以创建新的.npy文件并将NumPy数组数据写入其中,以便与其他Python或C++应用程序共享数据。

  3. 支持多种NumPy数据类型cnpy库支持NumPy中的多种数据类型,包括整数、浮点数、复数、布尔值等,以便适应各种科学计算需求。

  4. 跨平台支持cnpy库是跨平台的,可在多种操作系统上使用,包括Windows、Linux和macOS。

  5. 灵活性:该库允许用户指定数据的存储顺序(如C风格和Fortran风格存储),以满足不同数据来源的需求。

cnpy库的使用使C++开发人员能够与Python中使用NumPy的同事轻松共享和处理数据,从而更容易实现跨语言数据交互。这对于需要在C++应用程序中处理科学数据或与Python中的数据分析工具进行集成的项目非常有用。库的源代码和文档通常可以在GitHub上找到。

cnpy 示例 详解 C++

cnpy 是一个用于处理.npy文件的C++库,允许你读取和写入NumPy数组数据。下面是一个简单的示例,展示如何在C++中使用cnpy库读取.npy文件、修改数据,然后将数据写回.npy文件的过程。

首先,确保你已经安装了cnpy库并设置好了开发环境。你可以在项目的GitHub页面上找到库的源代码和详细文档,然后进行编译和安装。

假设有一个名为example.npy的.npy文件,其中包含一个NumPy数组。以下是示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include "cnpy.h"

int main() {
// 读取.npy文件
cnpy::NpyArray arr = cnpy::npy_load("example.npy");

// 获取NumPy数组的数据指针和形状
float* data = arr.data<float>();
std::vector<size_t> shape = arr.shape;

// 修改数据(这里将所有元素乘以2)
for (size_t i = 0; i < shape[0]; i++) {
data[i] *= 2;
}

// 创建一个新的.npy文件来保存修改后的数据
cnpy::npy_save("modified_example.npy", data, shape, "w");

std::cout << "Data has been modified and saved as 'modified_example.npy'." << std::endl;

return 0;
}

这个示例代码做了以下几件事:

  1. 使用cnpy::npy_load函数读取名为example.npy的.npy文件,将数据加载到cnpy::NpyArray对象中。

  2. NpyArray对象中获取数据指针和数组的形状。

  3. 修改数据。在这个示例中,我们将所有元素乘以2,但你可以根据需要进行任何修改。

  4. 使用cnpy::npy_save函数将修改后的数据保存为一个新的.npy文件,名为modified_example.npy。请注意,我们传递了参数 “w”,表示写入模式。

这样,你就能在C++中使用cnpy库读取、处理和保存NumPy数组数据了。这对于处理科学数据、跨语言数据交互以及与Python中的数据分析工具集成非常有用。

简介

  • dlib库笔记

dlib库 是什么

dlib库是一个C++库,用于进行机器学习、图像处理和计算机视觉任务。它提供了一系列功能,包括人脸检测、人脸关键点检测、面部表情分析、对象检测、图像处理等。dlib库在计算机视觉领域中非常受欢迎,因为它提供了高效且可靠的实现,广泛用于学术界和工业界的项目中。此外,dlib库还提供了Python接口,使得在Python环境下使用这些功能变得更加便捷。

dlib库 详解

dlib库是一个功能强大的C++库,主要用于机器学习、图像处理和计算机视觉任务。下面是对dlib库的一些主要功能和特性的详细解释:

  1. 人脸检测和人脸关键点检测

    • dlib库提供了高效的人脸检测器,能够在图像中准确地定位人脸的位置。
    • 它还提供了人脸关键点检测器,可以检测出人脸的关键点,如眼睛、鼻子、嘴巴等位置。
  2. 面部表情分析

    • dlib库可以进行面部表情分析,识别出人脸的表情,如快乐、悲伤、惊讶等。
  3. 对象检测

    • 除了人脸检测之外,dlib库还支持对象检测,能够识别出图像中的其他物体,如汽车、猫、狗等。
  4. 图像处理

    • dlib库提供了许多图像处理功能,包括图像变换、滤波、边缘检测等,这些功能可以帮助用户对图像进行预处理或增强。
  5. 机器学习算法

    • dlib库包含了许多机器学习算法的实现,如支持向量机(SVM)、k近邻(k-NN)、决策树等,这些算法可用于分类、回归等任务。
  6. 计算机视觉工具

    • dlib库提供了一些计算机视觉工具,如图像配准、图像匹配等,这些工具可以帮助用户处理图像数据并提取有用信息。
  7. 跨平台支持

    • dlib库在多个平台上都可以运行,包括Windows、Linux和macOS,用户可以在不同的操作系统上使用相同的代码。
  8. Python接口

    • dlib库提供了Python接口,使得在Python环境下使用这些功能变得更加方便。用户可以使用Python调用dlib库中的函数,并结合其他Python库进行开发。

总的来说,dlib库是一个功能强大且灵活的工具,适用于各种机器学习、图像处理和计算机视觉任务,因此在学术界和工业界都得到了广泛的应用。

简介

  • YAML 基础知识

yaml是什么

YAML(YAML Ain’t Markup Language的递归缩写)是一种人类可读的数据序列化格式。它常用于配置文件和数据交换格式,特别适用于各种编程语言之间的数据传递。

YAML的设计目标之一是提供一种易读且简洁的表示方法,以区别于其他常见的数据交换格式,如JSON(JavaScript Object Notation)和XML(eXtensible Markup Language)。相对于其他格式,YAML更注重人类可读性,其语法结构主要基于缩进和简洁的标记。

以下是一个简单的YAML示例,表示一个包含一些信息的简单结构:

1
2
3
4
name: John Doe
age: 30
city: New York
is_student: false

在上面的例子中,每一行都是一个键值对,用冒号分隔。缩进表示层次结构,例如nameagecity是顶级键,而is_student是其中一个嵌套的键。与其他格式相比,YAML更加人类可读,因为它不需要额外的符号和标记。

YAML广泛用于各种场景,包括配置文件、CI/CD流水线配置、数据序列化等。

YAML 详解

YAML(YAML Ain’t Markup Language)是一种用于表示数据序列化的格式,其设计目标是提供一个易读且简洁的文本表达方式。下面是一些关于YAML的详细解释:

  1. 基本语法

    • 键值对:使用冒号(:)将键和值分隔。
      1
      key: value
    • 列表:使用连字符(-)表示列表项,列表项可以包含简单的值或者嵌套的键值对。
      1
      2
      3
      - item1
      - item2
      - key: value
    • 嵌套结构:使用缩进表示层次结构。
      1
      2
      3
      parent:
      child1: value1
      child2: value2
  2. 数据类型

    • 字符串:可以使用单引号或双引号括起来,也可以不使用引号。
      1
      2
      3
      string1: 'single quoted'
      string2: "double quoted"
      string3: unquoted
    • 整数和浮点数:直接表示数字。
      1
      2
      integer: 42
      float: 3.14
    • 布尔值:可以使用 truefalse 表示。
      1
      boolean: true
  3. 注释:以井号(#)开头表示注释。

    1
    2
    # This is a comment
    key: value
  4. 多行文本:使用竖线符号(|)表示多行文本块,保留换行符。

    1
    2
    3
    4
    multiline: |
    This is a
    multiline
    text block.
  5. 折叠多行文本:使用右尖括号(>)表示折叠多行文本块,将换行符替换为空格。

    1
    2
    3
    4
    folded: >
    This is a folded
    multiline
    text block.
  6. 引用:可以使用 & 创建锚点,使用 * 引用锚点。

    1
    2
    3
    4
    parent: &anchor
    key: value

    reference: *anchor
  7. 特殊值

    • null 表示空值。
      1
      key: null
  8. 更多示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    user:
    name: John Doe
    age: 30
    is_student: false

    colors:
    - red
    - green
    - blue

    settings:
    enable_feature: true
    timeout: 5000

总体而言,YAML是一种灵活且易读的数据格式,广泛用于配置文件、数据交换和其他应用场景。在使用时,要注意缩进和空格的正确使用,因为它们在YAML中起着重要的语法作用。

yaml 基本语法 详解

YAML(YAML Ain’t Markup Language)的基本语法非常简洁和直观,以下是对其基本语法要点的详解:

  1. 键值对

    • 使用冒号(:)将键和值分隔。
    • 键值对的格式为 key: value
    1
    2
    name: John Doe
    age: 30
  2. 列表

    • 使用连字符(-)表示列表项。
    • 列表项可以包含简单的值或者嵌套的键值对。
    1
    2
    3
    4
    fruits:
    - apple
    - banana
    - orange
  3. 嵌套结构

    • 使用缩进表示层次结构,通常使用空格进行缩进。
    • 缩进的空格数可以不同,但同一层次必须保持一致。
    1
    2
    3
    4
    5
    6
    person:
    name: John Doe
    age: 30
    address:
    city: New York
    zip: '10001'
  4. 字符串

    • 字符串可以使用单引号或双引号括起来,也可以不使用引号。
    • 使用引号可以避免一些特殊字符引起的歧义。
    1
    2
    3
    single_quoted: 'This is a single-quoted string.'
    double_quoted: "This is a double-quoted string."
    unquoted: This is an unquoted string.
  5. 整数和浮点数

    • 直接表示数字,可以是整数或浮点数。
    1
    2
    integer: 42
    float: 3.14
  6. 布尔值

    • 使用 truefalse 表示布尔值。
    1
    is_student: false
  7. 注释

    • 使用井号(#)表示注释,注释可以单独一行或在行尾添加。
    1
    2
    # This is a comment
    key: value # Comment at the end of a line
  8. 多行文本

    • 使用竖线符号(|)表示多行文本块,保留换行符。
    1
    2
    3
    4
    multiline: |
    This is a
    multiline
    text block.
  9. 折叠多行文本

    • 使用右尖括号(>)表示折叠多行文本块,将换行符替换为空格。
    1
    2
    3
    4
    folded: >
    This is a folded
    multiline
    text block.
  10. 引用

    • 可以使用 & 创建锚点,使用 * 引用锚点。
    1
    2
    3
    4
    parent: &anchor
    key: value

    reference: *anchor
  11. 特殊值

    • null 表示空值。
    1
    key: null

这些基本语法要点构成了YAML的基础,使其适用于多种场景,特别是作为配置文件或数据交换格式。在使用YAML时,注意缩进和空格的正确使用是非常重要的,因为它们直接影响文档的结构。

CPP中常用的YAML解析工具

除了YAML-cpp之外,还有一些其他常用的C++ YAML解析工具,这些工具提供了不同的功能和特性,可以根据项目需求选择合适的工具。以下是一些常见的C++ YAML解析工具:

  1. YAML-cpp:YAML-cpp是一个流行的C++库,用于解析和生成YAML数据。它提供了简单易用的API,支持YAML 1.2规范,并且可以在多种平台上使用。上面提供的示例代码演示了如何使用YAML-cpp。

  2. LibYAML:LibYAML是一个C库,但也有C++绑定可供使用。它是一个高性能的YAML解析器和生成器,支持YAML 1.2规范。虽然它在C++中需要使用C绑定,但它在处理大型YAML文件时性能出色。

  3. YAML-cpp-Parser:这是一个建立在YAML-cpp之上的库,用于更方便地解析YAML数据。它提供了更简洁的API,可以帮助简化解析过程。

  4. yaml-cpp03:这是YAML-cpp的一个旧版本,与C++03标准兼容。如果你的项目需要C++03支持,可以考虑使用此版本。

  5. yaml-cpp11:这是YAML-cpp的C++11版本,支持现代C++标准。它在C++11及更高版本中使用时更适用。

  6. **YAML++**:YAML++是另一个C++ YAML解析库,它提供了类型安全的API和更高级的功能,如自定义类型序列化和反序列化。

  7. SimpleYAML:SimpleYAML是一个轻量级的C++库,用于处理YAML数据。它设计简单,易于学习和使用,适用于小型项目和快速原型开发。

  8. Boost.PropertyTree:虽然Boost.PropertyTree不是专门用于YAML的库,但它支持多种数据格式,包括JSON和INI,可以用于解析YAML文件。这个库是Boost C++库集合的一部分。

根据项目的具体要求和C++标准的选择,你可以选择适合你需求的YAML解析工具。不同的工具在性能、易用性和功能方面可能有所不同,因此选择合适的工具非常重要。在使用任何库之前,建议查看其文档和示例以了解如何正确使用。

yaml数组

在 YAML (YAML Ain’t Markup Language) 中,数组(或列表)是一种用于表示多个值的结构。YAML 支持两种方式来定义数组:一是使用连字符(-)作为前缀的列表,二是使用方括号([])包裹的逗号分隔值的方式。

1. 使用连字符的数组

这种方式在 YAML 中是最常见的,适合定义多行的列表。

1
2
3
4
fruits:
- Apple
- Banana
- Orange

输出为:

1
fruits: [Apple, Banana, Orange]

2. 使用方括号的数组

这种方式适合单行定义数组。

1
fruits: [Apple, Banana, Orange]

这两种方式的功能是等效的。使用哪一种主要取决于格式的需求和个人的习惯。

YAML 数组中的每个元素是一个数组

在 YAML 中,如果数组的每个元素都是一个数组,可以通过多级缩进来表示。例如,使用 - 来表示数组的每一层,格式如下:

1
2
3
4
5
6
7
8
9
10
matrix:
- - 1
- 2
- 3
- - 4
- 5
- 6
- - 7
- 8
- 9

在这个例子中:

  • matrix 是一个数组,其中的每个元素都是一个嵌套的数组。
  • 每个嵌套的数组在 matrix 下又包含多个元素。

你也可以将这些元素放在同一行来简化结构:

1
2
3
4
matrix:
- [1, 2, 3]
- [4, 5, 6]
- [7, 8, 9]

这样也能表示一个二维数组,其中 matrix 是一个包含三个数组的数组,每个内部数组包含 3 个数字。这种格式特别适合表示矩阵或表格数据结构。

YAML 嵌套数组

在 YAML 中,嵌套数组可以通过缩进的方式来实现。具体语法如下:

  1. 普通数组:使用短横线 - 表示数组元素。
  2. 嵌套数组:在数组的某个元素下,再次使用短横线并进行适当缩进,来定义嵌套数组的层次结构。

以下是一个 YAML 嵌套数组的示例:

1
2
3
4
5
6
7
8
9
10
11
fruits:
- apple
- banana
- berries:
- strawberry
- blueberry
- raspberry
- citrus:
- orange
- lemon
- lime

在这个例子中:

  • fruits 是一个数组,包含 4 个元素。
  • 第三个元素 berries 和第四个元素 citrus 是对象,这些对象的值是一个数组。

也可以用更深层次的嵌套数组:

1
2
3
4
5
6
7
8
9
library:
- name: Fiction
books:
- title: "The Great Gatsby"
- title: "To Kill a Mockingbird"
- name: Science
books:
- title: "A Brief History of Time"
- title: "The Selfish Gene"

这里 library 是一个包含多个对象的数组,每个对象包含一个 books 数组。

这种 YAML 结构适用于表示复杂的树状数据。只要按照正确的缩进格式来写,就能顺利定义出嵌套数组。

简介

  • 文件传输协议:文件传输是数据交换的主要形式,在进行文件传输时,为使文件能被正确识别和传送,需要在两台计算机之间建立统一的传输协议。这个协议包括了文件的识别,传送的起止时间,错误的判断与纠正等内容

  • 在SecureCRT下的传输协议有ASCII, XMODEM, YMODEM, ZMODEM

    • ASCII:这是最快的传输协议,但只能传送文本文件
    • XMODEM: 这种古老的传输协议速度较慢,但是由于使用了CRC错误侦测方法,传输的准确里可高达99.6%。XMODEM是一种在串口通信中广泛使用的异步文件传输协议。分为XMODE和1k-XMODEM协议两种,前者使用128字节的数据块,后者使用1024字节即1k字节的数据块
    • YMODEM:这个个是XMODEM的改良版,使用了1024位区段传送,速度比XMODEM要快
    • ZMODEM:这个采用了串流式(streaming)传输方式,传输速度较快,而且还具有自动改变区段大小和断点续传,快速错误侦测等功能,这是目前最流行的文件传输协议。
  • Windows下生成md5校验码: certutil -hashfile filename MD5

  • Linux下生成md5校验码: md5sum filename

  • xshell 传输文件

    • sz filename

psmisc adduser libc6 libcurl4 libdevmapper1.02.1 libgcc1 libgl1 libopus0 libpng16-16 libqt5core5a libqt5gui5 libqt5opengl5 libqt5printsupport5 libqt5widgets5 libqt5x11extras5 libsdl1.2debian libssl1.1 libstdc++6 libvpx5 libx11-6 libxcb1 libxcursor1 libxext6 libxml2 libxt6 zlib1g

简介

  • face_recognition库

face_recognition库 是什么

face_recognition库是一个用于人脸识别的Python库。它建立在dlib、OpenCV和NumPy等库之上,提供了简单而强大的接口,用于识别图像或视频中的人脸并进行匹配。face_recognition库的主要功能包括:

  1. 人脸检测:能够在图像或视频中检测出人脸的位置。

  2. 人脸特征提取:提取出人脸图像的特征向量,用于后续的比较和识别。

  3. 人脸识别:将提取的人脸特征与已知的人脸特征进行比较,从而识别人脸。

  4. 人脸标志点检测:检测出人脸图像中的关键点,如眼睛、鼻子、嘴巴等位置。

  5. 实时人脸识别:能够在视频流中进行实时的人脸识别。

face_recognition库的简单接口和易用性使得人脸识别变得更加容易,不需要深入了解复杂的机器学习算法或计算机视觉技术。因此,它在各种应用场景中都有着广泛的应用,包括安全监控、人脸解锁、社交媒体应用等。

face_recognition库 详解

face_recognition库是一个基于Python的人脸识别工具,它建立在dlib、OpenCV和NumPy等库之上,提供了简单而强大的接口,用于识别图像或视频中的人脸并进行匹配。下面是face_recognition库的一些详细解释:

  1. 人脸检测face_recognition库使用基于深度学习的方法,能够在图像或视频中快速准确地检测出人脸的位置。

  2. 人脸特征提取:一旦检测到人脸,face_recognition库会提取出人脸图像的特征向量。这些特征向量是通过深度学习模型生成的,具有较高的表征能力。

  3. 人脸识别:提取的人脸特征向量可以用于后续的比较和识别。face_recognition库提供了简单的接口,让用户可以将提取的特征向量与已知的人脸特征进行比较,从而识别人脸。

  4. 人脸标志点检测:除了识别人脸,face_recognition库还能够检测出人脸图像中的关键点,如眼睛、鼻子、嘴巴等位置。这些关键点对于许多人脸相关任务非常有用。

  5. 实时人脸识别face_recognition库支持在视频流中进行实时的人脸识别。这意味着它可以应用于需要实时响应的场景,如安全监控系统或人脸解锁应用等。

  6. 简单易用的接口face_recognition库提供了简单易用的Python接口,使得人脸识别变得更加容易。用户不需要深入了解复杂的机器学习算法或计算机视觉技术,只需几行代码就可以完成人脸识别任务。

总的来说,face_recognition库是一个功能强大且易于使用的人脸识别工具,适用于各种应用场景,包括安全监控、人脸解锁、社交媒体应用等。

简介

  • 互联网专业名词的笔记

POC

POC展示是指将Proof of Concept(POC)演示给相关利益相关者、观众或用户的过程。在计算机安全领域,当安全研究人员或漏洞猎人发现一个漏洞,并成功开发了POC代码来证明其存在和影响时,他们通常会进行POC展示。

POC展示的目的是以实际的方式展示漏洞的潜在威胁或攻击效果。通过演示POC,安全研究人员可以向利益相关者、安全社区、软件开发商或系统管理员展示漏洞的实际工作原理和可能的影响。这种展示通常是以技术演示、演讲、演示视频或实际的操作演示的形式呈现。

POC展示的目的是增强人们对漏洞的认识,并促使相关方采取适当的措施来修复漏洞或提高系统的安全性。此外,POC展示也有助于推动安全研究和漏洞披露的进程,促进安全社区的知识共享和交流。

需要注意的是,在进行POC展示时,安全研究人员应该遵循道德和法律规定,确保在合适的环境中、合法的授权下进行演示,避免对他人的系统和数据造成未经授权的伤害或损失。

总而言之,POC展示是指将POC演示给相关观众或利益相关者的过程,旨在以实际的方式展示漏洞的工作原理和可能的影响,促使相关方采取适当的安全措施。


OEM

OEM协作是指原始设备制造商(Original Equipment Manufacturer)之间的合作关系和协作活动。在OEM协作中,一个公司(被称为“下游OEM”)与另一个公司(被称为“上游OEM”)合作,通常是为了共同开发、制造或销售某种产品。

下游OEM通常是产品的最终制造商,他们使用上游OEM提供的组件、零部件、技术或知识来生产和组装最终产品。下游OEM可能没有自己的生产能力或专业技术,因此他们与上游OEM合作,以便从上游OEM那里获得所需的资源和支持。

上游OEM则是提供组件、零部件、技术或知识的供应商。他们与下游OEM合作,为其提供所需的产品、技术或专业知识,以支持下游OEM的生产和组装过程。上游OEM通常拥有先进的研发和制造能力,可以为下游OEM提供高质量的组件和解决方案。

OEM协作可以带来多方面的好处,例如:

  1. 专业技术支持:上游OEM可以提供技术咨询、培训和支持,帮助下游OEM提高产品质量和生产效率。

  2. 成本效益:通过与上游OEM合作,下游OEM可以获得成本效益,因为他们可以利用上游OEM的规模经济和采购能力来获得更好的价格和供应链优势。

  3. 加快产品开发和上市时间:通过与上游OEM合作,下游OEM可以共享上游OEM的研发成果和技术,从而加快产品的开发和上市时间。

  4. 扩大市场份额:OEM协作可以帮助下游OEM扩大市场份额,通过与上游OEM的品牌合作或合作销售,吸引更多的客户和业务机会。

OEM协作是供应链管理中常见的合作模式之一,可以帮助各方在产品开发、制造和销售方面互相支持和受益。

简介

  • protobuf库 笔记

C++ protobuf是什么

Protocol Buffers(ProtoBuf)是由Google开发的一种轻量级、高效的数据交换格式,同时也是一种用于序列化结构化数据的协议。ProtoBuf 可以被用于多种应用场景,最常见的是在数据通信和数据存储中。

以下是对 Protocol Buffers 的一些主要特点和用法的解释:

主要特点:

  1. 可读性和可扩展性: ProtoBuf 使用二进制格式,相比于 XML 和 JSON 等文本格式,更加紧凑、高效。尤其在大规模数据传输场景下,ProtoBuf 的性能更为优越。

  2. 数据结构定义: 使用简洁的语法定义结构化的数据模型。定义的数据结构称为消息(Message),通过 Protobuf 编译器生成对应的代码,用于序列化和反序列化数据。

    1
    2
    3
    4
    5
    6
    7
    syntax = "proto3";

    message Person {
    required string name = 1;
    required int32 id = 2;
    optional string email = 3;
    }
  3. 跨语言支持: ProtoBuf 生成的代码支持多种编程语言,包括 C++, Java, Python, Go, Ruby, C#, JavaScript 等,使得数据在不同平台和语言间的交换变得简便。

  4. 版本兼容性: ProtoBuf 具有向前和向后兼容性,允许在不破坏现有数据的情况下进行协议的演化。

  5. 高性能: 序列化和反序列化速度快,占用的存储空间相对较小,适用于对性能有要求的场景。

使用步骤:

  1. 定义消息: 使用 Protocol Buffers 的语法定义消息的数据结构。

    1
    2
    3
    4
    5
    6
    7
    syntax = "proto3";

    message Person {
    required string name = 1;
    required int32 id = 2;
    optional string email = 3;
    }
  2. 编译器生成代码: 使用 Protobuf 编译器(protoc)将消息定义文件编译为相应语言的代码。

    1
    protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/person.proto
  3. 使用生成的代码: 在程序中使用生成的代码进行消息的序列化和反序列化。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // 使用生成的代码
    #include "person.pb.h"

    // 创建 Person 对象
    Person person;
    person.set_name("John");
    person.set_id(123);

    // 序列化为字节流
    std::string serialized_data = person.SerializeAsString();

    // 反序列化
    Person deserialized_person;
    deserialized_person.ParseFromString(serialized_data);

ProtoBuf 提供了简单、高效、可扩展的数据交换格式,广泛用于网络通信、存储、配置文件等场景。其优秀的性能和跨语言支持使得它成为许多大型项目和分布式系统中的首选数据格式。

C++ protobuf 详解

Protocol Buffers(ProtoBuf)是一种由Google设计的轻量级、高效的数据交换格式。它不仅用于定义数据结构,还提供了一种机制来序列化和反序列化这些数据。在 C++ 中,ProtoBuf 的使用涉及定义 .proto 文件、使用 Protocol Buffers 编译器(protoc)生成代码,以及在代码中使用生成的代码进行序列化和反序列化。

以下是使用 C++ 的 ProtoBuf 的基本步骤:

步骤 1:定义 .proto 文件

首先,定义一个 .proto 文件来描述你的数据结构。例如,下面是一个简单的示例:

1
2
3
4
5
6
7
syntax = "proto3";

message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
}

在这个示例中,定义了一个 Person 消息,包含 nameid 和可选的 email 字段。

步骤 2:使用 protoc 编译器生成代码

使用 protoc 编译器将 .proto 文件编译成相应语言的代码。在 C++ 中,你需要生成 C++ 代码,可以使用以下命令:

1
protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/person.proto

其中,$SRC_DIR 是存放 .proto 文件的目录,$DST_DIR 是生成的 C++ 代码存放的目录。

步骤 3:使用生成的代码

在你的 C++ 代码中,使用生成的代码进行序列化和反序列化。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "person.pb.h"

int main() {
// 创建 Person 对象
Person person;
person.set_name("John");
person.set_id(123);

// 序列化为字节流
std::string serialized_data = person.SerializeAsString();

// 反序列化
Person deserialized_person;
deserialized_person.ParseFromString(serialized_data);

// 使用反序列化后的数据
std::cout << "Name: " << deserialized_person.name() << std::endl;
std::cout << "ID: " << deserialized_person.id() << std::endl;
std::cout << "Email: " << deserialized_person.email() << std::endl;

return 0;
}

在这个示例中,我们使用生成的 person.pb.h 头文件中的 Person 类进行数据的操作。SerializeAsString() 方法用于将对象序列化为字符串,而 ParseFromString() 方法用于从字符串中反序列化对象。

注意事项:

  • 字段规则: ProtoBuf 支持的字段规则包括 requiredoptionalrepeated。在 ProtoBuf 3 中,required 已经被废弃,建议使用 optionalrepeated

  • 默认值: ProtoBuf 支持给字段设置默认值。在序列化时,如果字段的值等于默认值,则不会写入到输出流中。

  • 扩展性: ProtoBuf 具有良好的扩展性,可以通过扩展消息和字段来进行协议的演化,同时保持向前和向后兼容性。

  • 更多特性: ProtoBuf 还支持枚举、嵌套消息、扩展等高级特性,可以根据具体需求进行使用。

总体而言,ProtoBuf 提供了一种高效、紧凑、可扩展的数据交换格式,适用于各种场景,特别是对性能和数据大小有要求的应用程序。

简介

  • leveldb 库 笔记

C++ leveldb是什么

LevelDB(Level DataBase)是一个由Google开发的开源键值对存储库。它是一个基于 C++ 编写的持久化键值对存储引擎,设计用于提供快速的键值查询和范围查询。

以下是 LevelDB 的一些主要特点和特性:

主要特点:

  1. 键值对存储: LevelDB 是一个键值对存储引擎,每个键和值都是任意字节序列。这使得 LevelDB 能够存储和检索各种类型的数据。

  2. 快速读写: LevelDB 提供了高性能的读写操作。它的设计目标是在随机读写和迭代范围查询方面都具有良好的性能。

  3. 支持快照: LevelDB 支持快照(Snapshot),允许在不受并发写入影响的情况下进行读取操作。

  4. 支持批量写入: LevelDB 支持批量写入(Write Batch),可以一次性提交多个写入操作,提高写入效率。

  5. 支持前缀查询: LevelDB 支持按前缀进行范围查询,这对于检索某个特定前缀的所有键值对非常有用。

  6. 支持单一写入者多读取者: LevelDB 支持单一写入者和多读取者,写入者和读取者可以并发操作,提高并发性。

  7. 可移植性: LevelDB 可以在不同的平台上运行,并提供了各种语言的绑定,包括 C++、Java、Python 等。

LevelDB 的使用:

LevelDB 提供了简单的 C++ 接口,允许开发者通过 C++ 代码与 LevelDB 进行交互。以下是一个简单的 LevelDB 使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include "leveldb/db.h"

int main() {
leveldb::DB* db;
leveldb::Options options;
options.create_if_missing = true;

leveldb::Status status = leveldb::DB::Open(options, "/path/to/db", &db);
if (!status.ok()) {
std::cerr << "Unable to open database: " << status.ToString() << std::endl;
return -1;
}

// 写入数据
leveldb::WriteOptions writeOptions;
status = db->Put(writeOptions, "key1", "value1");
if (!status.ok()) {
std::cerr << "Error writing to database: " << status.ToString() << std::endl;
delete db;
return -1;
}

// 读取数据
leveldb::ReadOptions readOptions;
std::string value;
status = db->Get(readOptions, "key1", &value);
if (status.ok()) {
std::cout << "Value for key1: " << value << std::endl;
} else {
std::cerr << "Error reading from database: " << status.ToString() << std::endl;
}

delete db;
return 0;
}

在此示例中,LevelDB 被用于打开数据库、写入数据、读取数据等操作。注意,这只是一个简单的示例,实际应用中可能需要更多的错误处理和配置选项。

C++ leveldb库 详解

LevelDB 是一个由Google开发的开源键值对存储引擎,提供了一个轻量级、高性能的数据存储解决方案。下面是对 LevelDB 库的一些详细解释:

LevelDB 主要特性:

  1. 键值对存储: LevelDB 是一个键值对存储引擎,每个键和值都是任意字节序列。这使得它适用于多种类型的数据。

  2. 快速读写: LevelDB 设计用于提供高性能的读写操作。它在大量的数据读取和写入场景中表现得相当出色。

  3. 支持快照: LevelDB 支持快照,允许在进行读取操作时创建数据的快照,从而避免被并发写入所影响。

  4. 支持批量写入: 提供了批量写入操作,允许一次性提交多个写入操作,从而提高写入效率。

  5. 支持前缀查询: LevelDB 支持按前缀进行范围查询,对于需要检索某个特定前缀的所有键值对的场景非常有用。

  6. 单一写入者多读取者: LevelDB 支持单一写入者和多读取者,使得写入者和读取者能够并发操作,提高了并发性。

  7. 数据持久性: 提供持久性数据存储,确保数据在系统重启后仍然可用。

LevelDB 的基本用法:

以下是使用 LevelDB 的基本用法,包括数据库的打开、读写操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "leveldb/db.h"

int main() {
// 打开数据库
leveldb::DB* db;
leveldb::Options options;
options.create_if_missing = true;
leveldb::Status status = leveldb::DB::Open(options, "/path/to/db", &db);

if (!status.ok()) {
std::cerr << "Unable to open database: " << status.ToString() << std::endl;
return -1;
}

// 写入数据
leveldb::WriteOptions writeOptions;
status = db->Put(writeOptions, "key1", "value1");
if (!status.ok()) {
std::cerr << "Error writing to database: " << status.ToString() << std::endl;
delete db;
return -1;
}

// 读取数据
leveldb::ReadOptions readOptions;
std::string value;
status = db->Get(readOptions, "key1", &value);
if (status.ok()) {
std::cout << "Value for key1: " << value << std::endl;
} else {
std::cerr << "Error reading from database: " << status.ToString() << std::endl;
}

// 关闭数据库
delete db;

return 0;
}

在这个例子中,首先打开 LevelDB 数据库,然后进行写入和读取操作,最后关闭数据库。

LevelDB 的其他用法和配置:

  • 迭代器(Iterator): LevelDB 提供了迭代器用于遍历数据库中的键值对。

  • 删除数据: 使用 Delete 方法可以删除数据库中的键值对。

  • 配置选项: LevelDB 提供了丰富的配置选项,可以用于调整数据库的行为,如设置缓存大小、压缩选项等。

  • 并发控制: LevelDB 提供了基本的并发控制机制,允许多个读取者和一个写入者并发操作。

  • 性能调优: 可以通过调整参数和配置选项来优化 LevelDB 的性能,特别是在处理大规模数据时。

总体而言,LevelDB 是一个灵活、高性能的键值对存储引擎,适用于多种应用场景,特别是需要快速读写和持久化存储的场景。

简介

  • vcpkg

vcpkg 常用命令

vcpkg 是一个 C/C++ 项目的包管理工具,用于简化在 Windows、Linux 和 macOS 等平台上管理第三方库的过程。以下是一些常用的 vcpkg 命令:

  1. 安装包:

    1
    vcpkg install <package_name>

    例如:

    1
    vcpkg install zlib
  2. 卸载包:

    1
    vcpkg remove <package_name>

    例如:

    1
    vcpkg remove zlib
  3. 列出所有可用的包:

    1
    vcpkg search
  4. 列出已安装的包:

    1
    vcpkg list
  5. 升级已安装的包:

    1
    vcpkg upgrade
  6. 查看特定包的信息:

    1
    vcpkg info <package_name>

    例如:

    1
    vcpkg info zlib
  7. 在项目中使用已安装的包:

    1
    vcpkg integrate install

    这个命令会自动将所需的配置设置添加到项目中,使得项目能够找到和使用 vcpkg 安装的包。

  8. 清理已安装的包:

    1
    vcpkg remove --outdated

    这会删除已安装的过时包。

  9. 更新 vcpkg 本身:

    1
    2
    git pull origin master
    ./bootstrap-vcpkg.sh

    或者

    1
    vcpkg update

    注意:第一种方法需要在 vcpkg 目录下执行,第二种方法则可以在任何地方执行。

  10. 帮助:

    1
    vcpkg help

    或者

    1
    vcpkg help <command>

    例如:

    1
    vcpkg help install

这些是 vcpkg 中的一些常用命令,可以帮助你管理项目依赖的第三方库。