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

clang 编译器前端 分析

clang 编译器前端 分析

clang的python接口教程(二)

Python接口clang解析C语言AST抽象语法树

clang static analyzer源码分析

clang静态代码分析是clang相对于gcc一个比较能够引起关注的点,特别是clang静态代码分析基于checker的架构和大部分的静态分析工具都不相同。clang静态代码分析使用符号执行的技术执行路径敏感的代码分析,符号执行引擎并不实际进行报错,而是使用挂载在引擎上的checker对程序状态进行检查并报错。这种方式方便用户对代码检查规则或者bug类型进行扩展,但是这种架构也有其缺陷,符号执行完成一条语句后,clang静态分析引擎会遍历checker列表中的回调函数进行报错,也就是说checker的数量越多,clang静态分析扫描代码的速度越慢(clang静态分析引擎的速度是不变的)。

AnalysisASTConsumer 继承自ASTConsumer,是一个虚基类,只提供了一个添加报错机制的纯虚函数。

clang静态分析checker提供了两种方法,一种是遍历AST进行语法层级的报错,例如位运算符的操作数是有符号整数等,这些直接从AST树上拿到相关信息就可以直接报错,另外一种是需要构建CFG并在其上进行符号执行实现路径敏感的代码分析,关于这个,就有人曾经问过我,clang静态分析中CFG和AST的关系是什么。现在我们从这个类的继承体系就可以看出,clang静态代码分析是继承自于ASTConsumer,也就是说无论是基于AST的检查还是基于CFG的检查都是在AST上实现的,因为构建CFG也需要AST的协助。

pyclang 使用

 win10上安装LLVM 作用:能够安装各种libpip install clang 作用:作为调用clangAPI的接口,注意这个clang只是一个接口目录AST树中调用的函数都在 D:\ProgramFiles\python3.6.8\Lib\site-packages\clang\cindex.pyfrom clang.cindex import Index
类Index索引类型,clang.cindex库的主接口,通过提供一个接口来读写来解析翻译
index = Index.create() 创建一个索引
index.parse(filepath, 解析文件的路径
args=None, 额外参数通过命令行参数添加
Unsaveed_file=None, 列表,一项是映射文件名字 一项是替换内容
options=0) 其他参数

import clang.cindex
from clang.cindex import Index  #主要API
from clang.cindex import Config  #配置
from clang.cindex import CursorKind  #索引结点的类别
from clang.cindex import TypeKind    #节点的语义类别
from clang.cindex import TokenKind   #单词# clang.cindex需要用到libclang.so共享库,所以先配置共享库
libclangPath = r'D:/Program Files/LLVM/bin/libclang.dll'#这个路径需要自己先在笔记本上安装	
if Config.loaded == True:print("Config.loaded == True:")#pass
else:Config.set_library_file(libclangPath)print("install path")# 创建AST索引
file_path = r"test.c"
index = Index.create()tu = index.parse(file_path)
AST_root_node= tu.cursor  #cursor根节点
print(AST_root_node)#前序遍历AST
'''
前序遍历严格来说是一个二叉树才有的概念。这里指的是对于每个节点,先遍历本节点,再遍历子节点的过程。
'''
node_list = []
def preorder_travers_AST(cursor):# 函数声明 CursorKind.FUNCTION_DECL 查找if  (not CursorKind._kinds[cursor._kind_id] is None) and cursor.kind == CursorKind.FUNCTION_DECL:# 函数被定义的地方if cursor.is_definition():# 打印有定义的函数名 有函数体的 函数print(cursor.spelling + " " + str(cursor.extent.start.file)) # 函数名和所在的文件名# cursor.extent.start.line, cursor.extent.start.column  # 起始行列#  cursor.extent.end.line, cursor.extent.end.column     # 终止行列# 遍历该函数代码 经词法分析得到的每一个单词 tokenfor token in cursor.get_tokens():# 如果是 c/c++ 等语言关键字if token.kind == TokenKind.KEYWORD:if token.spelling == "static":# 出现在 函数名 之前的 static 标记,该函数为静态函数print("this func is static" )elif token.spelling == cursor.spelling: # 如果已经遇到函数名了 则 该函数不是 静态函数print("this func is not static" )break# 遍历函数内容for child in cursor.get_children():# 查找函数参数 CursorKind.PARM_DECLif (not CursorKind._kinds[child._kind_id] is None) and child.kind == CursorKind.PARM_DECL:print("param: "child.spelling )# 查找函数调用 CursorKind.CALL_EXPRif (not CursorKind._kinds[cursor._kind_id] is None) and cursor.kind == CursorKind.CALL_EXPR:  print("func call: "child.spelling" )# 函数语句if (not CursorKind._kinds[child_node._kind_id] is None) and child_node.kind == CursorKind.COMPOUND_STMT:for stmt in child_node.get_children():# 打印语句print(stmt.spelling)# 若未进来,说明是空函数else# 有可能被定义过得 函数 被多次声明# 这里虽然没有定义但是名字在上面分支出现,也是有定义的print(cursor.spelling + " current have not body")for cur in cursor.get_children():#do something#print(cur.spelling)preorder_travers_AST(cur)preorder_travers_AST(AST_root_node)输出
mainprintf
printf
printf"hello world\n"# 提取每个分词token 的方法。
cursor_content=""
for token in AST_root_node.get_tokens():
#针对一个节点,调用get_tokens的方法。print(token.spelling)

前端clang分析

Clang是LLVM的C/C++前端,从原理上他会产生用于后端的IR指令。但实际上Clang会有两种执行方式: 我们可以使用”-###”观察Clang的执行过程

1. 以Driver的方式执行: 会自动调用相关后端程序,并生成可执行文件,这也是之所以Clang虽然只是前端,却可以直接产生目标代码的原因.在驱动模式下,clang实质只是一个调度管理程序.2. 作为编译器-cc1前端方式运行:最后仅生成LLVM IR 

Clang执行初期是作为driver执行的,因此,程序的入口是:tools/driver/driver.cpp;

代码位置

如果不是-cc1,则进行相关命令解释,生成相容的命令行

通过Driver建立与GCC相容的编译过程,并由TheDriver.ExecuteCompilation执行该相容的

注意因为clang两种工作模式下,驱动模式实际是在补足参数后再通过-cc1的方式执行;

在Driver方式下,只是为clang补齐相关执行的各参数,如类库的名字,然后是通过“系统”执行clang -cc1命令,而并没有在“内部”继续clang的其余的操作;此时,clang会等待相关的执行操作完成后执行下一个命令(如ld)

驱动方式过程:

1。Parse:Option Parsing 编译参数解析在这个阶段完成后,命令行将被分解为具有适当参数定义好的选项。2. Pipeline:编译动作构造(Compilation Action Construction) 编译流水线构造

子进程作业树需要确认构造编译序列。这包含确认输入文件及其类型、对他们进行什么样的工作(预处理、编译、汇编、链接等)并为每个人物构造动作实例链表。这样的结构是一个或更多的顶层动作列表,每个通常对应一个单一的输出(例如,对象或链接的可执行文件)多数的动作(Actions)对应一个实际的任务,但是这里有两个特殊的任务(Actions),第一个是InputActions,他只是简单将输入参数匹配到另一个Actions的输入。第二个是BindArchAction,从概念上给所有使用输入的动作替换架构Clang驱动可以使用命令“-ccc-print-phases”转印这一阶段的结果。

2.5 Action

每次的 option 都会完整的走一遍从预处理,静态分析,backend 再到汇编的过程。

下面列下一些编译器的前端 Action,大家可以一个个用着玩。

InitOnlyAction - 只做前端初始化,编译器 option 是    -init-only
PreprocessOnlyAction - 只做预处理,不输出,编译器的 option 是 -Eonly
PrintPreprocessedAction - 做预处理,子选项还包括-P、-C、-dM、-dD 具体可以查看PreprocessorOutputOptions 这个类,编译器 option 是 -E
RewriteIncludesAction - 预处理
DumpTokensAction - 打印token,option 是 -dump-tokens
DumpRawTokensAction - 输出原始tokens,包括空格符,option 是 -dump-raw-tokens
RewriteMacrosAction - 处理并扩展宏定义,对应的 option 是 -rewrite-macros
HTMLPrintAction - 生成高亮的代码网页,对应的 option 是 - emit-html
DeclContextPrintAction - 打印声明,option 对应的是 -print-decl-contexts
ASTDeclListAction - 打印 AST 节点,option 是 -ast-list
ASTDumpAction - 打印 AST 详细信息,对应 option 是 -ast-dump
ASTViewAction - 生成 AST dot 文件,能够通过 Graphviz 来查看图形语法树。 option 是 -ast-view
AnalysisAction - 运行静态分析引擎,option 是 -analyze
EmitLLVMAction - 生成可读的 IR 中间语言文件,对应的 option 是      -emit-llvm
EmitBCAction - 生成 IR Bitcode 文件,option 是                   -emit-llvm-bc
MigrateSourceAction - 代码迁移,option 是 -migrate3. Bind:Tool & Filename Selection 工具、文件绑定

Bind 主要是与工具链 ToolChain 交互
根据创建的那些 Action,在 Action 执行时 Bind 来提供使用哪些工具,比如生成汇编时是使用内嵌的还是 GNU 的,还是其它的呢,这个就是由 Bind 来决定的,具体使用的工具有各个架构,平台,系统的 ToolChain 来决定

驱动与工具链互动去执行工具绑定(The driver interacts with a ToolChain to perform the Tool bindings)。每个工具链包含特定架构、平台和操作系统等编译需要的所有信息;一个单一的工具在编译期间需要提取很多工具链,为了与不同体系架构的工具进行交互。

这一阶段不会直接计算,但是驱动器可以使用”-ccc-print-bindings”参数打印这一结果,会显示绑定到编译序列的工具链,工具,输入和输出。

4. Translate:Tool Specific Argument Translation 工具参数翻译

当工具被选择来执行特定的动作,工具必须为之后运行的编译过程构造具体的命令。主要的工作是翻译gcc格式的命令到子进程所期望的格式。

5.Execute  工具执行

其执行过程大致如下:Driver::ExecuteCompilation -> Compilation::ExecuteJobs -> Compilation::ExecuteCommand-> Command::Execute -> llvm::sys::ExecuteAndWait;此时执行的ExecuteAndWait为Support/Program.cpp中的程序,其调用相关操作系统,执行其系统相关的执行程序,并等待执行过程完成。

clang cc1前端运行 真正有意义的前端操作

    auto FirstArg = std::find_if(argv.begin() + 1, argv.end(),[](const char *A) { return A != nullptr; });if (FirstArg != argv.end() && StringRef(*FirstArg).startswith("-cc1")) {// If -cc1 came from a response file, remove the EOL sentinels.if (MarkEOLs) {auto newEnd = std::remove(argv.begin(), argv.end(), nullptr);argv.resize(newEnd - argv.begin());}return ExecuteCC1Tool(argv);}  

如果是 -cc1 的话会调用 ExecuteCC1Tool 这个函数,先看看这个函数

static int ExecuteCC1Tool(ArrayRef<const char *> argv) {llvm::cl::ResetAllOptionOccurrences();StringRef Tool = argv[1];void *GetExecutablePathVP = (void *)(intptr_t) GetExecutablePath;if (Tool == "-cc1")return cc1_main(argv.slice(2), argv[0], GetExecutablePathVP);if (Tool == "-cc1as")return cc1as_main(argv.slice(2), argv[0], GetExecutablePathVP);if (Tool == "-cc1gen-reproducer")return cc1gen_reproducer_main(argv.slice(2), argv[0], GetExecutablePathVP);// Reject unknown tools.return 1;
}

最终的执行会执行 cc1-main 、cc1as_main 、cc1gen_reproducer_main。这三个函数分别在 driver.cpp 同级目录里的 cc1_main.cpp 、cc1as_main.cpp 、cc1gen_reproducer_main.cpp中。

依照关于Driver的示意图,clang将藉由Action完成具体的操作,在clang中所有action定义在include/clang/Drivers名字域:clang::driver下,其Action即其派生的Actions定义如下:

这一阶段完成,编译过程被分为一组需要执行并产生中间或最终输出(某些情况下,类似-fsyntax-only,不会有“真实”的最终输出)的Action。阶段是我们熟知的编译步骤,类似:预处理、编译、汇编、链接等等。

所有相关Action的定义在FrontendOptions.h(clang/include/clang/Frontend/FrontendOptions.h )中;

代码

在clang中允许通过FrontendAction编写自己的Action,使用FrontendPluginRegistry(clang/frontend/FrontendRegistry.h)注册自己的Action:其核心是通过继承clang::FrontendAction来实现,详细示例参考:clang/examples/AnnotateFunctions/AnnotateFunctions.cpp,该示例通过继承PluginASTAction,并使用FrontendPluginRegistry::Add将其注册

细节分析

clang 在线文档

最初的C/C++源码经过:词法分析(Lexical analysis)-> 语法分析(Syntactic analysis)-> 语义分析(Semantic analysis)-> 与平台无关的IR(LLVM IR generator)

从词法分析开始——将C语言 源码分解成token流,每个token可表示标识符、字面量、运算符等;
token流会传递给语法分析器,语法分析器会在语言的CFG(Context Free Grammar,上下文无关文法)的指导下将token流组织成AST(抽 象语法树);接下来会进行语义分析,检查语义正确性,然后生成IR。

libclang clang-c/Index.h c接口调用clang 示例

Parser部分涉及到的目录有 tools/clang/lib/AST语法树定义,Sema语义分析,Lex词法分析器,Parse语法分析器。

1. 词法分析(Lexical analysis) clang/lib/Lex/

token

词法分析器读入组成源程序的字节流,并将他们组成有意义的词素(Lexeme)序列。对于每个词素,词法分析器产生词单元(token)作为输出,并生成相关符号表。词法库包含了几个紧密相连的类,他们涉及到词法和C源码预处理。

相关诊断: clang/include/clang/Basic/DiagnosticLexKinds.td

词法单元(Token)的定义:TokenKinds.def(clang/include/clang/Basic/)

Clang的保留字定义在 TokenKinds.def,如常见的if或for关键字

说明TokenKinds.def中定义了许多诸如TOK和KEYWORD等宏,实际相关宏只有在外部引用程序引用TokenKinds.def前定义才会真正有意义;而且引用位置不同,其意义可能不同

Preprocessor类 ----- 返回下一个Token

Preprocessor是词法分析中的一个主要接口,可以看到,词法分析时在预处理过程中初始化的即Preprocessor.

在词法分析中,预处理程序被初始调用的主要程序是CompilerInstance::createPreprocessor(lib/Frontend/CompilerInstance.cpp)

之后是 FrontEnd Action -> /clang/lib/Lex/Preprocessor.cpp

其核心程序是Preprocessor::Lex,该程序返回下一个Token

Token类 clang/include/clang/Lex/Token.h

Token类用于表述电仪的词法单元。Token被用于词法/预处理单元,但并不会在这些库以外存在(如,Token不会存在于AST中).
Token.h

2. 语法分析(Syntactic analysis) libclangParse libclangAST

语法分析主要是解析词法分析产生的词法单元(token)并生成抽象语法树(ATS)。如同自然语言一样,语法分析并不检查语法的上下文的合理性,其仅仅是从语法角度确认是否正确。

语法分析的核心数据结构:Decl、Stmt、Type对应于声明、指令、类型。所有的被Clang描述的C/C++类都是继承于这三个类

源码 clang/lib/Parse/ 和clang/lib/AST/

诊断信息 DiagnosticParseKinds.td

语法分析器是使用递归下降(recursive-descent)的语法分析。

clang的Parser是由clang::ParseAST执行的。

libclangAST:

    提供了类用于:表示C AST、C类型、内建函数和一些用于分析和操作AST的功能(visitors、漂亮的打印输出等)源码定义:lib/AST重要的AST节点:Type、Decl、DeclContext、Stmt

Type类和他的派生类 clang/lib/AST/Type.cpp

Type类及其派生类是AST中非常重要的一部分。通过ASTContext访问Type(clang/ast/ASTContext.h),在需要时他隐式的唯一的创建他们。Type有一些不明显的特征:1)他们不捕获类似const或volatile类型修饰符(See QualType);2)他们隐含的捕获typedef信息。一旦创建,type将是不可变的。

声明,Decl类 clang/AST/DeclBase.h

表示一个声明(declaration)或定义(definition)。例如:变量、typedef、函数、结构等

声明上下文,DeclContext类 clang/AST/DeclBase.h

程序中每个声明都存在于某一个声明上下文中,类似翻译单元、名字空间、类或函数。Clang中的声明上下文是由类DeclContext类进行描述:各种AST节点声明上下文均派生于此(TranslationUnitDecl、NamespaceDecl、RecordDecl、FunctionDecl等)

DeclContext类对于每个声明上下文提供了一些公用功能:

  1. 与源码为中心和语义为中心的声明视图

    DeclContext提供了两种声明视图:源码为中心视图准确表示源程序代码,包括多个实体的声明(参见再宣告和重载)。而语义为中心的视图表示了程序语义。这两个视图在AST构造时与语义分析保持同步。

2.在上下文中保存声明

每个声明上下文中都包含若干的声明。例如:C++类(被表示为RecordDecl)包含了一些成员函数、域、嵌套类型等等。所有这些声明都保存在DeclContext中:即可以由容器迭代操作获得

这个机制提供了基于源码视图的声明上下文视图。

  1. 在上下文中查找声明

由DeclarationName类型指定的声明在声明上下文中查找声明 lookup()

该机制提供了基于语义为中心的声明上下文视图

  1. 声明所有者

    DeclContext包含了所有在其中声明的声明上下文,并负责管理他们并以及序列化(反)他们所有声明都保存在声明上下文中,并可以查询每个保存在其中的声明信息。关于声明上下文可以查看词法和语义分析一节.

  2. 再宣告和重载

    在翻译单元中,公共的实体可能会被声明多次。

    表达式”f”在以源码为中心的和以语义为中心的上下文中的视图有所不同,在以源码为中心的声明上下文中,再宣告与他在源码中声明的位置有关。在语义为中心的视图中,会使用最近的视图替换最初的声明。而基于DeclContext::look操作将返回基于语义视图的上下文。

  3. 词法和语义上下文

对于每个声明可能存在两个不同的声明上下文:词法上下文,对应于源码视图的声明上下文。语义上下文对应于语法视图的。Decl::getLexicalDeclContext(clang/AST/DeclBase.h)返回词法声明上下文。而Decl::getDeclContext返回基于语义上下文,返回的两个值都是指向DeclContext的指针。

7.透明声明上下文(TransparentDeclaration Contexts)

现于枚举类型,Red是Color中的成员,但是,我们在Color外引用Red时并不需要限定名:Color;

8.多重定义的声明上下文(Multiply-DefinedDeclaration Contexts)

可以由DeclContext::isTransparentContext确认是否是透明声明。

Stmt 指令 类 clang/AST/Stmt.h for do goto return …

QualType类 查询类

QualType被设计为一个微不足道的、微小的通过传值用于高效查询的类。QualType的思想是将类型修饰符(const、volatile、restrict以及语言扩展所需的修饰符)与他们自己的类型分开保存。QualType概念上是一对“Type *”和他们的类型修饰符。类型限定符只是占用指针的低位。

声明名字(Declarationnames)

DeclarationName(clang/AST/DeclarationName.h)用来描述clang中的声明名字。声明在C族语言中有一些不同的形式。多数的声明被命名为简单的标识,例如:f(int x)中的声明f和x。在C++中,声明可以构造类的构造函数、类的析构函数、重载操作符合转换函数。

CFG类 控制流程图? (Context Free Grammar,上下文无关文法)

CFG是用于描述单个指令(Stmt *)的源码级控制流程图?。典型的CFG实例为构造函数体(典型的是一个CompoundStmt实例),但是也可以表示任何Stmt派生类的控制流。控制流图通常对给定函数执行流-或路径-敏感的分析特别有用。

3.语义分析(Semantic Analysis)

libclangSema

4. 中间代码生成(IR Generator) libclangCodeGen

libclangCodeGen

5. 其他库介绍

libclangAnaylysis:用于进行静态分析用的

libclangRewrite:编辑文本缓冲区(代码重写转换非常重要,如重构)

libclangBasic:诊断、源码定位、源码缓冲区抽象化、输入源文件的文件缓冲区

Clang诊断子系统是一个编译器与人交互的重要部分。诊断是当代码不正确或可疑时产生警告和错误。在clang中,每个诊断产生(最少)一个唯一标识ID、一个相关的英文、SourceLocation源码位置“放置一个^”和一个严重性(例如:WARNING或ERROR)。他可以选择包含一些参数给争端(如使用%0填充字串)以及相关源码区域。

Clang diagnostics Diagnostic::Level enum [ NOTE WARNING EXTENSION EXTWARN ERROR ]

SourceLocation:表示源代码的位置。See:clang/Basic/SourceLocation.h。SourceLocation因为被嵌入到许多AST中,因此,该类必须足够小。

SourceLocation:通常是和SourceManager一同使用,用于对一个位置信息的两条信息进行编码。见:clang/Basic/SourceManager.h

SourceRange:是SourceLocation.h中类,表示源码的范围:【first,last】。First和last都是SourceLocation

相关文章:

clang 编译器前端 分析

clang 编译器前端 分析 clang的python接口教程&#xff08;二&#xff09; Python接口clang解析C语言AST抽象语法树 clang static analyzer源码分析 clang静态代码分析是clang相对于gcc一个比较能够引起关注的点&#xff0c;特别是clang静态代码分析基于checker的架构和大部…...

3个月精通Python(基础篇)——第1天:Python和Vscode环境安装

安装 Python&#xff1a; 访问 Python 官网 下载 &#xff0c;下载最新的 Python 安装程序。 双击安装程序&#xff0c;按照提示进行安装设置即可。 在安装过程中&#xff0c;请勾选“Add Python X.X to PATH”选项&#xff0c;这样安装后 Python 会被自动添加到系统的环境变量…...

react native web RN webpack nginx 部署

# nginx配置 location /app {root html;index index.html;# url 切换时始终返回index.htmltry_files $uri /app/index.html; } # 图片样式缓存1年 location ~* /app.*\.(js|css|png|jpg)$ {access_log off;expires 365d; } # html/xml/json 文件不缓存 location ~* /app.…...

Jmeter性能测试之Beanshell解析并提取json响应

1&#xff1a;前置条件 将fastjson-1.2.49.jar包置于jmeter的lib目录下&#xff0c;并将该jar包添加到测试计划的Library中&#xff1b;否则会报&#xff1a;Typed variable declaration : Class: JSONObject not found in namespace的错误 2&#xff1a;解析思路 利用beansh…...

vue-echarts配置项详解

起因 最近接手了一个vue3项目&#xff0c;echarts用的是"vue-echarts": “^6.0.0”&#xff0c;每次查看文档的时候痛苦不已&#xff0c;找一个配置要花费大量时间&#xff0c;所以这篇文章&#xff0c;主要就是为了记录比较常见的一些配置。 主要会写三种图的配置…...

两个csv进行根据相同字段进行合并

源文件&#xff0c;第一列&#xff0c;编号0 目标文件&#xff0c; 编号3 根据社区名称进行匹配&#xff0c;然后将第一个csv文件的经纬度添加到第二个文件中。 import csvsource r"D:\000datasets\链家房价数据\2020去重后社区名称地理编码.csv" target r"…...

SolidWorks绘制Maxwell仿真用带桥接的三维平板螺旋线圈

文章目录 前言一、建立涡状线二、拉伸方法1&#xff08;建立工作面&#xff0c;较复杂&#xff09;三、拉伸方法2&#xff08;穿透&#xff0c;较简单&#xff09;四、建立桥接 前言 在使用Maxwell进行电磁场仿真时&#xff0c;经常需要绘制各种异形线圈&#xff0c;由于Maxwel…...

【每日一个知识点二】原型链

我都是想到啥写啥&#xff0c;丝毫没有规律。前面聊到箭头函数没有原型&#xff0c;就想到了再整理一篇原型链的。 原型 原型是JavaScript中对象的一个属性&#xff0c;它指向另一个对象&#xff0c;用于实现继承关系。每个对象都有一个原型属性__proto__&#xff0c;它指向它…...

placeholder样式自定义(uniapp 微信小程序、h5)

一、使用uniapp开发 ①第一种方式&#xff1a;&#xff08;写在行内&#xff09; <input type"text" placeholder"姓名" placeholder-style"font-size:28rpx;color:#999999;" />②第二种方式&#xff1a; &#xff08;给input加上placeho…...

【LeetCode】383. 赎金信

题目&#xff1a;383. 赎金信 由于此题只含有小写字母,并且magazine里面的字母不可重复使用. 故首先用一个长度为26的整形数组记录magazine里字母出现的次数。 再用这个整形数组跟ransomeNote进行遍历比较&#xff0c;当数组中出现-1时&#xff0c;说明false,否则true. 代码&am…...

【算力革命】算力架构

AI芯片可按架构分为CPU、GPU、FPGA、ASIC&#xff0c;各架构的优缺点可参考以下文章&#xff1a; CPU、GPU、FPGA、ASIC等AI芯片特性及对比_cpu gpu fpga_maopig的博客-CSDN博客 最近&#xff0c;新名词 DSA&#xff08;Domain Specific Architecture&#xff0c;特定领域架构…...

【视觉SLAM入门】4.3. (非线性最小二乘问题)优化算法实现-ceres和g2o, 图优化理论

"天道不争而善胜" 1. Ceres库1.1 名词解释1.2 具体例子1.3 C实现1. 定义代价函数2. 构建最小二乘问题3. 配置求解器&#xff0c;开始优化4. 优化完毕&#xff0c;查看结果 2. G2O(General Graphic Optimization)2.1 图优化2.2 具体例子2.3 C实现1. 定义顶点2. 定义边…...

vue Can‘t resolve ‘path‘

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default. This is no longer the case. Verify if you need this module and configure a polyfill for it. 这句话的意思是webpack 5之前是自动导入node一些核心模块的垫片&#xf…...

【JavaEE初阶】——第七节.Servlet入门学习笔记

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;JavaEE进阶 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01; 文章目录 前…...

vue项目登录页面实现记住用户名和密码

vue项目登录页面实现记住用户名和密码 记录一下实现的逻辑&#xff0c;应该分两步来理解这个逻辑 首次登录&#xff0c;页面没有用户的登录信息&#xff0c;实现逻辑如下&#xff1a; 用户输入用户名和密码登录&#xff0c;用户信息为名为form的响应式对象&#xff0c;v-model…...

数学建模-MATLAB三维作图

导出图片用无压缩tif会更清晰 帮助文档&#xff1a;doc 函数名 matlab代码导出为PDF 新建实时脚本或右键文件转换为实时脚本实时编辑器-全部运行-内嵌显示保存为PDF...

pytorch工具——使用pytorch构建一个神经网络

目录 构建模型模型中的可训练参数假设输入尺寸为32*32损失函数反向传播更新网络参数 构建模型 import torch import torch.nn as nn import torch.nn.functional as Fclass Net(nn.Module):def __init__(self):super(Net,self).__init__()#定义第一层卷积层&#xff0c;输入维…...

在CSDN学Golang云原生(Kubernetes Pod)

一&#xff0c;pod的定义与基本用法 在 Kubernetes 中&#xff0c;Pod 是最小的可部署单元&#xff0c;它包含一个或多个容器。使用 Golang 来定义和操作 Pod 时&#xff0c;需要使用 kubernetes/client-go 包提供的 API。 以下是 Golang 定义和基本用法 Pod 的示例&#xff…...

我开源了团队内部基于SpringBoot Web快速开发的API脚手架v1.7.0更新

什么是 rest-api-spring-boot-starter rest-api-spring-boot-starter 适用于SpringBoot Web API 快速构建让开发人员快速构建统一规范的业务RestFull API 不在去关心一些繁琐。重复工作&#xff0c;而是把重点聚焦到业务。 动机 每次Web API常用功能都需要重新写一遍。或者复…...

excel要如何自动累加某个单元格上方的所有单元格?

输入公式 SUM(INDIRECT("A1:A"&ROW()-1)) 运行实例如下图 注意图中b4&#xff0c;和b5单元格都输入相同的公式。 此方法可以避免写vba&#xff0c;以前此类问题的解决都是通过vba代码进行处理 对函数进行解析 主要使用了 INDIRECT() 2、公式说明&#xff1a;…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局&#xff1a;PCB行业的时代之问 在数字经济蓬勃发展的浪潮中&#xff0c;PCB&#xff08;印制电路板&#xff09;作为 “电子产品之母”&#xff0c;其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透&#xff0c;PCB行业面临着前所未有的挑战与机遇。产品迭代…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

使用 SymPy 进行向量和矩阵的高级操作

在科学计算和工程领域&#xff0c;向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能&#xff0c;能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作&#xff0c;并通过具体…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...

前端中slice和splic的区别

1. slice slice 用于从数组中提取一部分元素&#xff0c;返回一个新的数组。 特点&#xff1a; 不修改原数组&#xff1a;slice 不会改变原数组&#xff0c;而是返回一个新的数组。提取数组的部分&#xff1a;slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...

Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么&#xff1f;它的作用是什么&#xff1f; Spring框架的核心容器是IoC&#xff08;控制反转&#xff09;容器。它的主要作用是管理对…...