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类对于每个声明上下文提供了一些公用功能:
-
与源码为中心和语义为中心的声明视图
DeclContext提供了两种声明视图:源码为中心视图准确表示源程序代码,包括多个实体的声明(参见再宣告和重载)。而语义为中心的视图表示了程序语义。这两个视图在AST构造时与语义分析保持同步。
2.在上下文中保存声明
每个声明上下文中都包含若干的声明。例如:C++类(被表示为RecordDecl)包含了一些成员函数、域、嵌套类型等等。所有这些声明都保存在DeclContext中:即可以由容器迭代操作获得
这个机制提供了基于源码视图的声明上下文视图。
- 在上下文中查找声明
由DeclarationName类型指定的声明在声明上下文中查找声明 lookup()
该机制提供了基于语义为中心的声明上下文视图
-
声明所有者
DeclContext包含了所有在其中声明的声明上下文,并负责管理他们并以及序列化(反)他们所有声明都保存在声明上下文中,并可以查询每个保存在其中的声明信息。关于声明上下文可以查看词法和语义分析一节.
-
再宣告和重载
在翻译单元中,公共的实体可能会被声明多次。
表达式”f”在以源码为中心的和以语义为中心的上下文中的视图有所不同,在以源码为中心的声明上下文中,再宣告与他在源码中声明的位置有关。在语义为中心的视图中,会使用最近的视图替换最初的声明。而基于DeclContext::look操作将返回基于语义视图的上下文。
-
词法和语义上下文
对于每个声明可能存在两个不同的声明上下文:词法上下文,对应于源码视图的声明上下文。语义上下文对应于语法视图的。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接口教程(二) Python接口clang解析C语言AST抽象语法树 clang static analyzer源码分析 clang静态代码分析是clang相对于gcc一个比较能够引起关注的点,特别是clang静态代码分析基于checker的架构和大部…...

3个月精通Python(基础篇)——第1天:Python和Vscode环境安装
安装 Python: 访问 Python 官网 下载 ,下载最新的 Python 安装程序。 双击安装程序,按照提示进行安装设置即可。 在安装过程中,请勾选“Add Python X.X to PATH”选项,这样安装后 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:前置条件 将fastjson-1.2.49.jar包置于jmeter的lib目录下,并将该jar包添加到测试计划的Library中;否则会报:Typed variable declaration : Class: JSONObject not found in namespace的错误 2:解析思路 利用beansh…...

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

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

SolidWorks绘制Maxwell仿真用带桥接的三维平板螺旋线圈
文章目录 前言一、建立涡状线二、拉伸方法1(建立工作面,较复杂)三、拉伸方法2(穿透,较简单)四、建立桥接 前言 在使用Maxwell进行电磁场仿真时,经常需要绘制各种异形线圈,由于Maxwel…...

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

placeholder样式自定义(uniapp 微信小程序、h5)
一、使用uniapp开发 ①第一种方式:(写在行内) <input type"text" placeholder"姓名" placeholder-style"font-size:28rpx;color:#999999;" />②第二种方式: (给input加上placeho…...

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

【算力革命】算力架构
AI芯片可按架构分为CPU、GPU、FPGA、ASIC,各架构的优缺点可参考以下文章: CPU、GPU、FPGA、ASIC等AI芯片特性及对比_cpu gpu fpga_maopig的博客-CSDN博客 最近,新名词 DSA(Domain Specific Architecture,特定领域架构…...

【视觉SLAM入门】4.3. (非线性最小二乘问题)优化算法实现-ceres和g2o, 图优化理论
"天道不争而善胜" 1. Ceres库1.1 名词解释1.2 具体例子1.3 C实现1. 定义代价函数2. 构建最小二乘问题3. 配置求解器,开始优化4. 优化完毕,查看结果 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一些核心模块的垫片…...

【JavaEE初阶】——第七节.Servlet入门学习笔记
作者简介:大家好,我是未央; 博客首页:未央.303 系列专栏:JavaEE进阶 每日一句:人的一生,可以有所作为的时机只有一次,那就是现在!!! 文章目录 前…...

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

数学建模-MATLAB三维作图
导出图片用无压缩tif会更清晰 帮助文档: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__()#定义第一层卷积层,输入维…...

在CSDN学Golang云原生(Kubernetes Pod)
一,pod的定义与基本用法 在 Kubernetes 中,Pod 是最小的可部署单元,它包含一个或多个容器。使用 Golang 来定义和操作 Pod 时,需要使用 kubernetes/client-go 包提供的 API。 以下是 Golang 定义和基本用法 Pod 的示例ÿ…...

我开源了团队内部基于SpringBoot Web快速开发的API脚手架v1.7.0更新
什么是 rest-api-spring-boot-starter rest-api-spring-boot-starter 适用于SpringBoot Web API 快速构建让开发人员快速构建统一规范的业务RestFull API 不在去关心一些繁琐。重复工作,而是把重点聚焦到业务。 动机 每次Web API常用功能都需要重新写一遍。或者复…...

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

广州道可维斯受邀参加首届金蝶暨佛山数字化生态峰会
2023首届金蝶暨佛山数字化生态峰会,于7月28日在佛山隆重举行。此次大会由金蝶软件集团主办,共有超150家软件行业企业莅临参与,共同探讨数字化行业的最新动态和趋势。 活动当日,道可维斯的客户成功中心主任梁健,做了以“企业内容管…...

ubuntu远程控制小车 运行rviz时报错
我买的是wheeltec的小车,测试rgbd相机时想在ubuntu上的rviz中显示小车的姿态和看到的rgb和depth图,但是ubuntu中rostopic list和rviz都找不到小车发布的话题信息,运行rqt_image_view时可以显示图片信息。 最终wheeltec的技术人员lucas帮我找了…...

轻松实现自定义数据脱敏返回
学习目标: 实现简单的数据脱敏功能 例如: 学习自定义数据脱敏 学习内容: 使用到:泛型、反射 /*** * param obj 需要数据脱敏的对象* param par 那些字段需要脱敏* param <T>* return* throws Exception*/public static …...

pytorch 中_call_impl()函数
记录pytorch 版本中的 nn.Module() 重要函数 1. _call_impl() 1.1 torch1.7.1 版本 def _call_impl(self, *input, **kwargs):for hook in itertools.chain(_global_forward_pre_hooks.values(),self._forward_pre_hooks.values()):result hook(self, input)if result is n…...

openGauss学习笔记-22 openGauss 简单数据管理-HAVING子句
文章目录 openGauss学习笔记-22 openGauss 简单数据管理-HAVING子句22.1 语法格式22.2 参数说明22.3 示例 openGauss学习笔记-22 openGauss 简单数据管理-HAVING子句 HAVING子句可以让我们筛选分组后的各组数据。 WHERE子句在所选列上设置条件,而HAVING子句则在由…...

干货 | 常见电路板GND与外壳GND之间接一个电阻一个电容,为什么?
干货 | 常见电路板GND与外壳GND之间接一个电阻一个电容,为什么? 外壳是金属的,中间是一个螺丝孔,也就是跟大地连接起来了。这里通过一个1M的电阻跟一个0.1uF的电容并联,跟电路板的地连接在一起,这样有什么好…...

网络层协议总览
网络层协议总览 IPARP(地址解析协议)ICMP(网际控制报文协议)路由选择协议NAT(网络地址转换协议) 网络层的主要协议包括IP、ARP、RARP、ICMP、IGMP以及各种路由选择协议等。 IP IP协议是TCP/IP协议簇中的核…...

C++模拟实现list
1.首先要了解到vs底层的list链表是带头双向循环的链表。 所以首先就要看成员变量 那么就说明我们还需要构造一个Node的结构体,(typedef一下就好了,名字不影响) 现在就可以完成间的push_back函数了。 1.list的iterator 我们之前模…...

PostgreSQL PG16 逻辑复制在STANDBY 上工作 (译)
开头还是介绍一下群,如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题,有需求都可以加群群内有各大数据库行业大咖,CTO,可以解决你的问题。加群请联系 liuaustin3 ,在新加的朋友会分到2群(共…...

《零基础入门学习Python》第058讲:论一只爬虫的自我修养6:正则表达式2
上一节课我们通过一个例子(匹配 ip 地址)让大家初步了解到正则表达式的魔力,也让大家充分了解到学习正则表达式是一个相对比较困难的事情。所以这一节课我们将继续学习 正则表达式的语法。 我们依稀还记得在Python中,正则表达式是…...