关于嵌入式开发的一些信息汇总:C标准、芯片架构、编译器、MISRA-C

news2024/7/6 18:59:31

关于嵌入式开发的一些信息汇总:C标准、芯片架构、编译器、MISRA-C

  • 关于C标准
  • 芯片架构是什么?
  • 架构对芯片有什么作用?
    • arm架构
    • X86架构
    • mips架构
    • 小结
  • 编译器
    • LLVM是什么?
    • 前端在干什么?
    • 后端在干什么?
  • MISRA C的诞生

以前写过的一些零零散散的小结,也没有系统的整理过,慢慢把它们收集更新在这篇博文里面。
内容算是集大成者,有一些来自于网上的其它作者,在文后给出了原文链接。

后面还会专门做一期关于嵌入式的专栏,希望大家持续关注。

关于C标准

  • C是一门开发者语言。C要转为机器语言,才能运行在芯片上。

  • 语言的转化需要编译器,每种芯片有自己认识的机器语言格式,即指令集,需要独立的编译器,而芯片有多种架构,主流的有:X86、ARM、RISC-V和MIPS。

    • X86 英特尔和AMD在PC市场上主导多年,CISC指令集
    • ARM 在移动和便捷设备上有明显优势,32位RISC指令集
    • MIPS 在网关、机顶盒市场上很受cq欢迎,32/64位RISC指令集
    • RISC-V 出现晚发展快,在智能穿戴产品应用广泛,开放ISA架构
    架构发明时间特点代表厂商主要应用领域国内相关公司
    X861976年性能高,速度快,兼容性好英特尔 AMDPC、服务器中科曙光、浪潮信息
    MIPS1981年简洁、优化方便、高拓展性龙芯网关、机顶盒龙芯中科
    ARM1983年成本低、低功耗苹果、谷歌、IBM、华为移动端、网络设备中国长城、华为
    RISC-V2014年完全开源、精简、易于移植三星、英伟达、西部数据智能穿戴产品全志科技、兆易创新、北京君正
  • 指令集架构(ISA, Instrucion Set Architecture)定义了基本数据类型(BYTE/HALFWORD/WORD/…)、寄存器(Register)、指令、寻址模式、异常、或者中断的处理方式等。一台计算机的指令系统反映了该计算机的全部功能,机器类型不同,其指令系统也不同,因而功能也不同

  • 处理器分为精简指令集计算机(RISC)(Reduced Instruction Set Computer)和复杂指令集计算机(CISC)(Complex Instruction Set Computer)。

  • 不同的处理器(CPU)会用相应的汇编语言编写底层操作程序,而在写这个汇编语言的时候需要依照指令集架构这个规则,从而处理器进行操作。

  • CPU依靠指令来计算和控制计算机系统,每款CPU在设计时就规定了一系列与其硬件电路相配合的指令系统

芯片架构是什么?

如前文所述,芯片架构是指对芯片的类别和属性的描述。架构一词还和语境有关,提到soc时,一般指嵌入式处理核心的类型。提到X86和arm时,指的是指令集。

架构对芯片有什么作用?

如果把CPU看作是一个解释器,架构是算法,寄存器转换级电路(RTL)是算法的实现,那么更好的架构就是更好的算法。

arm架构

Arm是高级精简指令集的简称,是一个32位的精简指令集处理器架构。
其架构图如下:(该图来自于网络)
ARM架构图

结构说明如下:
ALU:有两个操作数锁存器、加法器、逻辑功能、结果以及零检测逻辑构成。
桶形移位寄存器:ARM采用了32位的桶形移位寄存器,这样可以使在左移右移n位、环移n位和算术右移n位等都可以一次完成。
高速乘法器:乘法器一般采用“加一移位”的方法来实现乘法。ARM为了提高运算速度,则采用两位乘法的方法,根据乘数的2位来实现“加一移位”运算;ARM高速乘法器采用32*8位的结构,这样,可以降低集成度(其相应芯片面积不到并行乘法器的1/3)。
浮点部件:浮点部件是作为选件供ARM构架使用。FPA10浮点加速器是作为协处理方式与ARM相连,并通过协处理指令的解释来执行。
控制器:ARM的控制器采用的是硬接线的可编程逻辑阵列PLA。

特点
(1)体积小、低功耗、低成本、高性能ARM被广泛应用在嵌入式系统中的最重要的原因 支持Thumb(16位)/ARM(32位)双指令集,能很好的兼容8位/16位器件;
(2)大量使用寄存器,指令执行速度更快;
(3)大多数数据操作都在寄存器中完成;
(4)寻址方式灵活简单,执行效率高;
(5)指令长度固定。
(6)Load_store结构:在RISC中,所有的计算都要求在寄存器中完成。而寄存器和内存的通信则由单独的指令来完成。而在CSIC中,CPU是可以直接对内存进行操作的,流水线处理方式。

X86架构

X86架构(The X86 architecture)是微处理器执行的计算机语言指令集,指一个intel通用计算机系列的标准编号缩写,也标识一套通用的计算机指令集合。其PC架构如下图所示:
X86架构

结构说明如下
CPU:大家都不陌生的名词,中央处理器,计算机的核心大脑。
北桥(North Bridge Chipset):北桥是电脑主板上的一块芯片,位于CPU插座边,起连接作用。
南桥芯片(South Bridge):是主板芯片组的重要组成部分,一般位于主板上离CPU插槽较远的下方,PCI插槽的附近,这种布局是考虑到所连接的I/O总线较多,离处理器远一点有利于布线。
内存:是计算机中重要的部件之一,是与CPU进行沟通的桥梁。计算机中所有程序的运行都是在内存中进行的,因此内存的性能对计算机的影响非常大。
显卡(Video card,Graphics card):全称显示接口卡,又称显示适配器,是计算机最基本配置、最重要的配件之一。
网卡:是工作在链路层的网络组件,是局域网中连接计算机和传输介质的接口,不仅能实现与局域网传输介质之间的物理连接和电信号匹配,还涉及帧的发送与接收、帧的封装与拆封、介质访问控制、数据的编码与解码以及数据缓存的功能等。
声卡:基本功能是把来自话筒、磁带、光盘的原始声音信号加以转换,输出到耳机、扬声器、扩音机、录音机等声响设备,或通过音乐设备数字接口(MIDI)使乐器发出美妙的声音。
SATA(Serial Advanced Technology Attachment,串行高级技术附件):是一种基于行业标准的串行硬件驱动器接口,是由Intel、IBM、Dell、APT、Maxtor和Seagate公司共同提出的硬盘接口规范。
硬盘:是电脑主要的存储媒介之一,由一个或者多个铝制或者玻璃制的碟片组成。碟片外覆盖有铁磁性材料。

mips架构

MIPS,全称为Microprocessor without Interlocked Pipeline Stage。采用5级指令流水线,能够以接近每个周期一条指令的速率执行。这在当时很罕见。它是一种采取精简指令集(RISC)的处理器架构,其特点为:

(1)包含大量的寄存器、指令数和字符。
(2)可视的管道延时时隙。

MIPS架构
1984年,John Hennessy离开斯坦福,创立了MIPS科技公司。并且在成立的第二年就推出了第一个芯片设计R2000。
1988年,MIPS推出了R3000。这款产品很快大获成功,销售超百万颗。不少公司的消费电子产品都用到了R3000,比如索尼的PS。美国首家电脑公司DEC、爱普生、日本电器等等知名企业也均是其客户。
1991年,MIPS就推出了64bit的R4000。其竞争对手Arm则直到2012年才开始大范围推广64bit处理器设计。
直到现在,仍可以在不少产品中找到身影。比如英特尔旗下的自动驾驶公司Mobileye就仍在广泛采用其技术。而家用路由器产品中,MIPS也并不鲜见。

MIPS的创始人John Hennessy和RISC-V之父Dave Patterson也渊源颇深。两人合作撰写了2本现在被广泛用于本科生、研究生课程的教科书:《计算机体系结构:量化研究方法》和《计算机组成与设计:硬件/软件接口》。

小结

对比总结

编译器

芯片是一个硬件接收的是二进制的指令,要想让自己的编程语言转化为编程指令,就需要一个编译器
这个部分的重要程度丝毫不亚于芯片本身。最近国内很多公司在做AI芯片,经常出现芯片很快就做出来了,但芯片受限于编译器无法发挥最大能效的窘境。总之,了解编译器还是很重要的。
这个系列讲讲如何用LLVM做一个最简单的编译器。万变不离其宗,其他复杂的编译器可以从这个例子上拓展。本部分主要讲基础知识,不需要了解细节,但是对编译器整体如何工作的要有概念。

LLVM是什么?

首先一个东西要搞明白,为什么要用LLVM? LLVM的是什么?

LLVM提供了一个模块化的编译器框架,让程序员可以绕开繁琐的编译原理,快速实现一个可以运行的编译器。主要由三个部分组成。

  • 前端:将高级语言例如C或者其他语言转换成LLVM定义的中间表达方式 LLVM IR。例如非常有名的clang, 就是一个转换C/C++的前端。
  • 中端:中端主要是对LLVM IR本身进行一下优化,输入是LLVM, 输出还是LLVM, 主要是消除无用代码等工作,一般来讲这个部分是不需要动的,可以不管他。
  • 后端:后端输入是LLVM IR, 输出是我们的机器码。我们通常说的编译器应该主要是指这个部分。大部分优化都从这个地方实现。

至此,LLVM架构的模块化应该说的比较清楚了,它的最大的一个特点是隔离了前后端。如果你想支持一个新语言,就重新实现一个前端,例如华为“仓颉”就有自己的前端来替换clang。如果你想支持一个新硬件,那你就重行实现一个后端,让它可以正确的把LLVM IR映射到自己的芯片。

接下来我们大致讲讲前后端的流程。

前端在干什么?

我们以Clang举例,我们以Clang举例,前端主要实现四件事,即经过词法分析、语法分析、语义分析、LLVM IR生产,最终将C++转化成后端认可的LLVM IR

词法分析:将编程语言取出一个个词,遇到不认识的字符就报错。例如将a=b+c 拆成a,= ,b ,+, c
语法分析:将语法提取出来,例如你写了个a+b=c, 明显不符合语法,直接报错
语义分析:分析一下你写的代码实际含义是不是对,例如a=b+c, a,b,c有没有定义,类型是不是对的
LLVM IR生产:经过上述三步,将你写的代码转化成树状描述(抽象语法树),然后再转化成IR定义的IR即可。

举个直观的栗子:

你写的C++如下: add.cpp
int add(int a, int b) {
return a + b;
}
生产的LLVM IR如下
(这个地方你不需要看懂每个细节,知道大概想类汇编的语言就行了, 专业的形式叫SSA, Static Single Assignment (SSA)
; ModuleID = ‘add.cpp’
source_filename = “add.cpp”
target datalayout = “e-m:o-i64:64-f80:128-n8:16:32:64-S128”
target triple = “x86_64-apple-macosx10.15.0”
; Function Attrs: noinline nounwind optnone ssp uwtable
define i32 @_Z3addii(i32, i32) #0 {
%3 = alloca i32, align 4
%4 = alloca i32, align 4
store i32 %0, i32* %3, align 4
store i32 %1, i32* %4, align 4
%5 = load i32, i32* %3, align 4
%6 = load i32, i32* %4, align 4
%7 = add nsw i32 %5, %6
ret i32 %7
}

后端在干什么?

后端把你的LLVM转换成真正的汇编(或者机器码),主要的流程如下。这个我们要重点讲讲,因为后续我们就是要实现一个这个东西支持一个新的芯片。先上图:
后端流程图
按步骤一个一个讲。
1、 DAG Lowering
这个主要负责将你的LLVM IR转换为有向无环图,便于后续利用图算法优化。
例如将下面的LLVM IR 转换成图,每个节点是一个指令。
LLVR转换图
2、 DAG Legalization
DAG图合法化,1中的DAG图都是LLVM IR指令,但实际上LLVM IR指令不可能被芯片全部支持,这个步骤就是替换这些不合法的指令。
DAG图合法化
3、 Instruction Selection
这个步骤其实和2算是一起的功能,都是为了将LLVM IR转换成机器支持的Machine DAG.
DAG图合法化
如上图,将store换成机器仍可的st, 将16位的寄存器转向32位。一切向机器指令靠拢。
4、 Scheduling
这个步骤主要是调整指令顺序的,从有向无环图再展开成顺序的指令。
例如把下面的指令调成这样的。
调指令顺序
把%C的store提前一些,因为下一条ld要用C啦。

5、 SSA-based Machine Code Optimization
这一步骤主要是做一些公共表达式合并啊去除的操作。
6、 Register Allocation
这一步就要分配寄存器了。在5之前我们认为寄存器其实是可以无限用的,但实际硬件的寄存器有限的,所以我们得考虑寄存器数量与寄存器值的生命周期,将虚拟的寄存器替换成实际的寄存器。这个一般会用到图着色等等算法,贼复杂,好在LLVM都实现好了,不用在重复造轮子。
例如一个芯片,有32个可用的寄存器,如果函数使用到了64个,多的就只能压入堆栈或者等着了。具体怎么分配的,知乎有专家研究,见下面的文章。Frank Wang:LLVM寄存器分配(一)
7、 Prologue/Epilogue Code Insertion
这个主要是加上函数调用前的指令和函数结束后的指令。主要是调用前把参数存下来,调用后把结果写到固定的寄存器里。
8、 Peephole optimizations
这个步骤主要是对代码再最后抢救一番。比如把x*2换成x<1。再比如下面这样,将两个32bit的存储换成一个64bit的存储。
32位替代64位
9、 Code Emission
最后一步显然,将上述优化好的中间格式转换成我们真正需要的汇编,由汇编器翻译成机器码,大功告成。

大佬的原文在此,请移步欣赏:
主流X86-ARM-RISC-V-MIPS芯片架构分析
主存储器和DRAM
内存基础知识

MISRA C的诞生

  • C语言紧凑、表达力强、功能强大。它为程序员提供了编写高效、可读和可维护代码的方法。所有这些功能都说明了它的受欢迎程度。不幸的是,该语言还使粗心的开发人员能够编写危险的、不安全的代码,这些代码可能会在开发项目的所有阶段和部署阶段导致严重问题。对于安全性和/或安全性是主要优先事项的应用程序,语言的这些缺点是一个主要问题。

  • 正是在这种背景下,在 1990 年代后期汽车工业软件可靠性协会 (MISRA) 推出了一套关于在车辆系统中使用 C 语言的指南,后来被称为 MISRA C。从那时起,该指南一直稳步发展完善,不时发布更新。还建立了使用 C++ 的类似方法。尽管该指南最初是针对汽车软件开发人员的,但很快人们就意识到它们同样适用于许多其他安全至关重要的应用领域,并且该标准现在已被许多行业广泛采用。

  • 尽管 MISRA C 不是风格指南——实际上许多用户应用风格指南和标准——许多规则也促进编写清晰、可读、可维护的代码。这是非常有益的,因为易于理解的代码不太可能包含细微的错误或未定义的行为。

  • 我的参考资料来自 MISRA C:2012 第三版,第一次修订版本。MISRA C 一直在接受审查,增量更改解决了指南的清晰度和准确性,并支持更新版本的 C 语言标准。尽管细节发生了变化,但总体理念和方法没有变化。
    引用其中几个作为示例说明。

    规则 13.2 – 表达式的值及其带来的副作用在所有被允许的评估顺序下应是相同的
    C 语言标准在表达式的求值顺序方面为编译器提供了非常广泛的自由度。因此,任何对评估顺序敏感的代码都是依赖于编译器的,并且依赖于编译器的代码应始终被视为不安全的。
    例如,自增自减运算符的使用可能会很麻烦:
    val = n++ + arr[n];
    访问了arr的哪个元素?程序员是否期望用于索引数组的n的值是递增之前或之后的值?虽然看起来好像增量是在数组索引之前执行的,但它假设了左右表达式求值,这不是一个有效的假设。所以,代码不清晰,应该这样重写:
    val = n + arr[n+1];
    n++;
    或者
    val = n++;
    val += arr[n];
    甚至
    值=n;
    n++;
    val += arr[n];
    您选择哪个选项取决于个人风格。它们都执行相同的操作,事实上,优化编译器很可能会生成完全相同的代码。
    在一个表达式中使用多个函数调用可能会出现类似的问题。函数调用可能会产生副作用,影响另一个函数。例如:
    val = fun1() + fun2();
    在这种情况下,如果其中一个函数可以影响另一个函数的结果,则代码是不明确的。要编写安全的代码,必须消除任何可能的歧义:
    val = fun1();
    val += fun2();
    现在很清楚fun1()先执行了。

    规则 17.2 – 函数不得直接或间接调用自身
    有时,表达算法的一种优雅方式是使用递归。然而,除非递归受到非常严格的控制,否则存在堆栈溢出的危险,这反过来又会导致很难定位错误。在安全关键代码中,应避免递归。

    规则 19.2 – 不应使用 union 关键字
    尽管 C 是一种类型化语言,但类型化并不是很严格,开发人员可能会试图覆盖类型化以“简化”他们的代码。遵守数据类型的约束对于创建安全代码至关重要,因为任何绕过数据类型的尝试都可能产生未定义的结果。union关键字可用于多种目的,这通常会导致代码不清晰,但也可以作为一种避免键入的方法。
    举个例子是使用联合来“拆开”一个无符号整数,因此:
    union e
    {
    unsigned int ui;
    无符号字符 a[4];
    }F;
    在这种情况下, ui的每个字节都可以作为a的一个元素来访问。但是,我们不能确定a[0]是否是最高有效字节中的最低字节,因为这是一个实现问题。(本质上与处理器的字节序相关联。)替代方法可能是使用移位和掩码,因此:
    unsigned char getbyte(unsigned int input, unsigned int index)
    {
    输入 >>= (index * 8);
    返回输入 & 0xff;
    }

可能有人会争辩说,这些规则(以及大多数(即使不是全部)MISRA C)只是常识,任何优秀的程序员都会采用这种方法。这可能是正确的,但一套明确的指导方针可以减少出错的机会

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

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

相关文章

使用国内镜像源安装opencv

在控制台输入命令&#xff1a; pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple 验证安装&#xff1a; step 1&#xff1a; 打开终端&#xff1b;step 2&#xff1a; 输入python&#xff0c;进入Python编译环境&#xff1b;step 3&#xff1a; 粘贴…

基于若依搭建微服务nacos版本(ruoyi-Cloud前后端分离)

说明&#xff1a;本文介绍基于Ruoyi-Cloud前后端分离nacos版本的微服务从0到1的搭建过程&#xff0c;同时新增一个新的微服务模块。是基于官方文档的补充说明&#xff0c;需要结合Ruoyi-Cloud的官方文档 https://doc.ruoyi.vip/ruoyi-cloud/ 如果直接查看官方文档便可成功部署&…

LeetCode刷题--- 全排列

个人主页&#xff1a;元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏 力扣递归算法题 【 http://t.csdnimg.cn/yUl2I 】 【C】 【 http://t.csdnimg.cn/6AbpV 】 数据结构与算法 【 http://t.csdnimg.cn/hKh2l 】 前言&…

hadoop3.3.4安装及启动

1.虚拟机的安装 此处我选择的是VMware,激活码可以百度搜索&#xff0c;安装过程比较缓慢&#xff0c;需要耐心等待 --------------------------------------------------------------------------------------------------------------------------------- 2.创建新的虚拟机…

虚幻学习笔记17—C++委托(单播)

一、前言 相比“代理”这个名词我更喜欢叫“委托”&#xff0c;虚幻的委托分为三类&#xff0c;分别为单播、多播和动态多播。单播顾名思义就是一次只能绑定一个函数的委托&#xff0c;多播能一次性绑定多个&#xff0c;动态多播即可以在蓝图中进行动态的绑定且可以绑定多个。 …

YOLOv8改进 | Conv篇 | 轻量级下采样方法ContextGuided(涨点幅度)

一、本文介绍 本文给大家带来的是改进机制是一种替换Conv的模块Context Guided Block (CG block) &#xff0c;其是在CGNet论文中提出的一种模块&#xff0c;其基本原理是模拟人类视觉系统依赖上下文信息来理解场景。CG block 用于捕获局部特征、周围上下文和全局上下文&#…

Leetcode—2413.最小偶倍数【简单】

2023每日刷题&#xff08;六十&#xff09; Leetcode—2413.最小偶倍数 class Solution { public:int smallestEvenMultiple(int n) {return (n % 2 1) * n;} };运行结果 之后我会持续更新&#xff0c;如果喜欢我的文章&#xff0c;请记得一键三连哦&#xff0c;点赞关注收藏…

新手HTML和CSS的常见知识点

​​​​ 目录 1.HTML标题标签&#xff08;到&#xff09;用于定义网页中的标题&#xff0c;并按照重要性递减排列。例如&#xff1a; 2.HTML段落标签&#xff08;&#xff09;用于定义网页中的段落。例如&#xff1a; 3.HTML链接标签&#xff08;&#xff09;用于创建链接…

小区生活污水处理需要哪些设备和工艺

在小区生活中&#xff0c;污水处理是一个非常重要的环节&#xff0c;它关乎到环境的保护和居民的生活质量。因此&#xff0c;了解小区生活污水处理所需要的设备和工艺是至关重要的。 首先&#xff0c;在小区生活污水处理中&#xff0c;需要用到的设备包括污水收集系统、初级沉淀…

详解RTC:以华人文化打造链上生态

文化是人类在发展的历史长河中淘洗出来的智慧结晶&#xff0c;随着人类社会的进步和变迁&#xff0c;经历了从口口相传到互联网等不同历史时代的传承和创新。在数字技术飞速发展的当今&#xff0c;区块链技术为文化的创新与传承提供了全新的空间和方式&#xff0c;使其得以在新…

【CANN训练营】CANN算子开发进阶笔记

Ascend C Tilling计算 Tilling基本概念介绍 大多数情况下&#xff0c;Local Memory的存储&#xff0c;无法完全容纳算子的输入与输出的所有数据&#xff0c;需要每次搬运一部分输入数柜进行计算然后搬出&#xff0c;再敲运下一部分输入数据进行计算&#xff0c;直到得到完愁的…

【深度学习】TensorFlow深度模型构建:训练一元线性回归模型

文章目录 1. 生成拟合数据集2. 构建线性回归模型数据流图3. 在Session中运行已构建的数据流图4. 输出拟合的线性回归模型5. TensorBoard神经网络数据流图可视化6. 完整代码 本文讲解&#xff1a; 以一元线性回归模型为例&#xff0c; 介绍如何使用TensorFlow 搭建模型 并通过会…

智能优化算法应用:基于松鼠算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于松鼠算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于松鼠算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.松鼠算法4.实验参数设定5.算法结果6.参考文献7.MA…

使用opencv的Laplacian算子实现图像边缘检测

1 边缘检测介绍 图像边缘检测技术是图像处理和计算机视觉等领域最基本的问题&#xff0c;也是经典的技术难题之一。如何快速、精确地提取图像边缘信息&#xff0c;一直是国内外的研究热点&#xff0c;同时边缘的检测也是图像处理中的一个难题。早期的经典算法包括边缘算子方法…

黑马头条--day01.环境搭建

一.前言 该项目学习自黑马程序员&#xff0c;由我整理如下&#xff0c;版权归黑马程序员所有 二.环境搭建 1.数据库 第一天&#xff0c;先创建如下库和表: sql文件如下: CREATE DATABASE IF NOT EXISTS leadnews_user DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_…

内存泄漏排查与预防

前言 内存泄漏问题&#xff0c;在C程序中经常会被开发测试人员忽略&#xff0c;最终会在客户运行现场因为内存泄漏最后导致程序内存耗尽&#xff0c;最后崩溃&#xff0c;从而影响客户的生产环境&#xff0c;导致异常发生。因为内存泄漏是一个共性的问题&#xff0c;所有的C程序…

html的学习笔记

开发工具&#xff1a;vscode 文字标签 h1:一级标题&#xff0c;h2&#xff1a;二级标题h6 p&#xff1a;段落标签 hr&#xff1a;分隔线 br&#xff1a;换行 strong/b&#xff1a;文字加粗 ins/u:下划线 em/i&#xff1a;倾斜 del/s&#xff1a;删除线 媒体标签 图片…

Vue前端与后端放在一起的搭建方式

1.首先把后端项目搭建好 去到项目的存放位置 2.然后cmd黑窗口输入命令创建vue项目 3.创建成功后回到后端项目进行合并 3.1在File处选择Project Structure 3.2选择模块 3.3找到自己的vue项目 3.4疯狂next最后create 3.5选择Apply并确定OK&#xff0c;恭喜您创建成功了 二、启动…

Star 4.1k!Gitee GVP开源项目!新一代桌面应用开发框架 ElectronEgg!

前言 随着现代技术的快速升级迭代及发展&#xff0c;桌面应用开发已经变得越来越普及。然而对于非专业桌面应用开发工程师在面对这项任务时&#xff0c;可能会感到无从下手&#xff0c;甚至觉得这是一项困难的挑战。 本篇文章将分享一种新型桌面应用开发框架 ElectronEgg&…

自动驾驶学习笔记(十八)——Lidar感知

#Apollo开发者# 学习课程的传送门如下&#xff0c;当您也准备学习自动驾驶时&#xff0c;可以和我一同前往&#xff1a; 《自动驾驶新人之旅》免费课程—> 传送门 《Apollo 社区开发者圆桌会》免费报名—>传送门 文章目录 前言 Lidar感知 运动补偿 点云分割 总结…