2312llvm,09clang工具下

ClangQuery

LLVM3.5中引入ClangQuery工具,它可读入一个源文件,交互查询它所关联的ClangAST节点.是帮助查看并学习前端如何表达每行代码的很好工具.

然而,它的主要目标是,你不但可查看程序的AST,而且可测试AST匹配器.

编写重构工具时,你会对使用,包含匹配感兴趣的ClangAST片段的断定(predicate)AST匹配器库感兴趣.
ClangQuery工具可在开发时帮助你,因为它让你可查看哪个AST节点匹配具体AST匹配器.

你可在ASTMatchers.h中,查看可用的AST匹配器的列表,但是也可根据驼峰大小写的名字,猜测感兴趣的AST节点的类.
如,functionDecl会匹配所有表示函数声明FunctionDecl节点.
试验了哪个匹配器确切返回感兴趣的节点后,可在重构工具中用它们实现自动转换方法.

如下查看AST,会对上次PPTrace中用到的"helloworld"代码运行clang-query.ClangQuery期望有编译命令数据库.
如果查看没有编译命令数据库的文件,就在双短划线后给出编译命令,或空着它,如果不需要特殊编译器选项,如下行所示:

$ clang-query hello.c --

发出该命令后,clang-query会显示一个等待输入命令的交互提示.可输入match命令和任意AST匹配器的名字.
如,下面命令中,让clang-query显示所有CallExpr节点:

clang-query> match callExpr()
Match #1:
hello.c:12:5: note: "root" node binds here
write(1, "Hello, ", 7);
^~~~~~~~~~~~~~~~~~~~~~
...

该工具会高亮程序中与关联CallExprAST节点对应的第一个令牌确切位置.ClangQuery可接受的命令列表如下:
1,help:打印命令列表.
2,match<matchername>m<matchername>:该命令用请求的匹配器遍历AST.
3,set output<(diag|print|dump)>:该命令在成功匹配后,修改如何打印节点信息.第一个选项会打印一个Clang诊断消息,并高亮节点,这是默认选项.

第二个选项会简单地打印匹配到的对应源码的摘要,而最后选项会调用带复杂调试功能并显示所有子节点dump()类成员函数.

了解程序ClangAST的结构的一个重要方法,是修改dump输出,并匹配高级节点.试试:

lang-query> set output dump
clang-query> match functionDecl()

它会显示在C源码中,构成所有函数体语句和式的所有实例.另一方面,记住,用ClangCheck可更容易得到的该完整AST转存.

ClangQuery更适造AST匹配器式并检查它们的结果.

ClangCheck

ClangCheck是个更易学习的只有几百行代码非常基础工具.然而,因为链接了LibTooling,它具有整个Clang解析能力.

ClangCheck可解析C/C++源码文件,转存ClangAST,及基础检查.还可应用Clang给出的"fixit"修改建议,利用为ClangModernizer建造的重写器设施.

如,假设想要打印program.cAST,就如下输入:

$ clang-check program.c -ast-dump --

注意,ClangCheckLibTooling读取源文件的方式,可用命令数据库文件,或在双短划线(--)后输入适当的参数.

ClangCheck是个小工具,编写自己工具时,可学习它.

去除c_str()调用

remove-cstr-calls工具是个简单的源到源转换(即重构)工具.工作时会识别冗余的调用std::string对象的c_str(),并重写代码来避免它.

有时会冗余调用,首先,用另一个string对象或c_str()的结果来建造新的string对象时,如,std::string(myString.c_str()).

这可简化为直接使用string拷贝构造器,如,str::string(myString).
其次,根据string对象来建造LLVM的具体的StringRefTwine类的实例时.

这时,最好用string对象自身,而不是其c_str()的结果,即用StringRef(myString),而不是StringRef(myString.c_str()).

可在单个C++文件里完整写出该工具,这是另一个优秀的易学习的演示如何使用LibTooling建造重构工具的示例.

编写自己的工具

Clang项目为用户提供了包括语法和语义分析的三个接口,以利用Clang的特性和它的解析能力.

首先,libclang是和Clang交互的主要方式,它提供了稳定的CAPI,允许外部项目嵌入它,并可高级访问整个框架.

该稳定接口保持旧版本兼容,避免因为发布新版的libclang而破坏你的软件.从其它语言使用libclang也是可能的,如,使用ClangPython绑定.
Apple的Xcode,如,它通过libclangClang交互.
其次,允许编译过程中添加自己的Clang插件,而不是由如Clang静态分析器等工具执行离线分析.

每次编译翻译单元都要执行它时,这是有用的.因此,要考虑期望执行该分析的时间,来决定是否适合频繁运行.

另一方面,与给编译器增加命令选项一样,整合分析构建系统,也很容易.

最后还可通过LibTooling利用Clang.以重构代码或检查语义为目标,它可轻松建造独立工具.

LibClang相比,LibTooling不与兼容妥协,可完全访问ClangAST结构.

问题:编写C++重构工具

假设创立新的叫IzzyC++C++IDE.
利用LibTooling制作简单而好用C++代码重构工具;它按C++成员函数,全名,和替换名接受参数.

任务是找到该成员函数定义,用替代名修改它,且相应修改所有对该函数的调用.

配置源码位置

第一步是决定在哪存放工具代码.在LLVM的源码目录中,将新建一个叫izzyrefactor的目录,在tools/clang/tools/extra中,保存项目的所有文件.

之后,扩展extra目录中的Makefile,以包含你的项目.简单,找到DIRS变量,并在其它Clang工具项目的旁边添加izzyrefactor名字.
或许还想编辑CMakeLists.txt文件,假如你使用CMake,添加新的一行:

add_subdirectory(izzyrefactor)

来到izzyrefactor目录,创建新的Makefile,以通知LLVM-build系统,要建造独立于其它二进制文件而存在的独立工具.如下:

CLANG_LEVEL := ../../..
TOOLNAME = izzyrefactor
TOOL_NO_EXPORTS = 1
include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support\mc option
USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a \clangDriver.a clangRewriteFrontend.a clangRewriteCore.a \clangParse.a clangSema.a clangAnalysis.a clangAST.a \clangASTMatchers.a clangEdit.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile

这是指定所有需要你的代码链接到一起的库的重要文件,这样才能建造该工具.
可选地,如果不想运行make install时,和其它LLVM工具一样安装新工具,在设置TOOL_NO_EXPORTS这行之后,可添加一行NO_INSTALL=1.

设置TOOL_NO_EXPORTS=1,因为工具不会使用插件,因此,不需要导出符号,减小了最终程序动态符号表的大小,也减少了动态链接加载程序的时间.

注意包含了定义了期望的所有规则Clang总的Makefile编译该项目.

如果使用CMake而不是自动工具配置脚本,用如下内容,创建新CMakeLists.txt文件:

add_clang_executable(izzyrefactorIzzyRefactor.cpp)
target_link_libraries(izzyrefactorclangEdit clangTooling clangBasic clangAST clangASTMatchers)

此外,如果不想在Clang源码树中构建该工具,你也可按独立工具构建它.

注意,前面Makefile中用的库,在USEDLIBS变量中,及在CLANGLIBS变量中用的库.

它们引用了相同的库,除了USEDLIBS有包含LibToolingclangTooling.因此,在Makefile中,在-lclang这行之后,添加一行-lclangTooling,就大功告成了.

剖析工具样板代码

所有代码在IzzyRefactor.cpp中.新建该文件并开始添加初始样板代码,如下:

int main(int argc, char **argv) {cl::ParseCommandLineOptions(argc, argv);string ErrorMessage;OwningPtr<CompilationDatabase> Compilations (CompilationDatabase::loadFromDirectory(BuildPath, ErrorMessage));if (!Compilations)report_fatal_error(ErrorMessage);//...
}

主要代码从llvm::cl名字空间的解析argv中的每个选项的ParseCommandLineOptions函数开始.

注意,基于LibTooling的工具,典型会使用为所有重构工具共享的CommonOptionsParser对象来轻松解析通用选项.这里

本例中,用低级的ParseCommandLineOptions()函数来确切说明要解析的参数.
所有的LLVM工具都会使用cl名字空间提供的功能,在命令行中,用工具识别定义的参数,实在是很简单.为此,声明新的opt模板类型和list全局变量:

cl::opt<string> BuildPath(cl::Positional,cl::desc("<build-path>"));
cl::list<string> SourcePaths(cl::Positional,cl::desc("<source0> [... <sourceN>]"),cl::OneOrMore);
cl::opt<string> OriginalMethodName("method",cl::desc("Method name to replace"),cl::ValueRequired);
cl::opt<string> ClassName("class",cl::desc("Name of the class that has this method"),cl::ValueRequired);
cl::opt<string> NewMethodName("newname",cl::desc("New method name"),cl::ValueRequired);

定义main函数前声明这五个全局变量.根据期望按参数读取的数据,指定了opt类型.如,如果需要读取数字,你会声明一个新的cl::opt<int>全局变量.

为了读取这些参数的数值,先要调用ParseCommandLineOptions.之后,只需要在期望关联数据类型的代码位置,引用与参数关联全局变量名.

如,如果代码像std::out<<NewMethodName期望串,NewMethodName会为该参数求值用户提供的串.

因为opt<>opt_storage<>父类模板,这工作,它定义了从所管理的数据类型(此处为string)继承的.

通过继承,opt<string>变量也是个.
如果opt<>类模板不能从被包装的数据类型(如,不存在的int类)继承,它会定义个类型转换符号,如为int数据类型,定义operator int().

代码中,效果是一样的;引用cl::opt<int>变量时,它会自动转换为一个整数,并返回它所存储的数字,即用户在命令行提供的数字.

还可为参数指定不同特征.示例中,通过指定cl::Positional使用了位置参数,即用户不会显示按名字指定参数,而是会根据在命令行中的相对位置推导出来.

还给opt构造器传递了一个desc对象,它定义了一段,用户在命令行中输入-help参数时,展示给用户的描述信息.

还有个使用cl::list类型的参数,不同于opt,它允许传递多个参数,这样可处理一堆源文件.要求包含下面头文件:

#include "llvm/Support/CommandLine.h"

注意,作为LLVM编码标准的一部分,include语句要,先包含本地头文件,随后包含ClangLLVMAPI头文件.

两个头文件属于相同分类时,按字母顺序排序.写独立工具,则自动为你整理头文件顺序.

最后三个全局变量设置用本重构工具的要求选项.第一个是-method名字的参数.第一个串参数指定没有短线参数名字,而cl::RequiredValues会通知命令行解析器,该值运行该程序所必需的.

该参数会给出方法名字,然后工具会去找该方法,然后用-newname给出的名字更改它的名字.-class参数给出有此方法类名.

下一段代码管理新的CompilationDatabase对象.首先,要包含定义OwningPtr类的头文件.

#include "llvm/ADT/OwningPtr.h"

注意Clang版本,从Clang/LLVM版本3.5开始,人们弃用了OwningPtr<>模板,而是转向C++标准的std::unique_ptr<>模板.

其次,要包含第一次用到的正式属于LibToolingCompilationDatabase类的头文件:

#include "clang/Tooling/CompilationDatabase.h"

该类负责管理编译数据库.
为了初化该对象,用到叫loadFromDirectory的工厂方法,它会从指定的构建目录加载编译数据库文件.

这就是按输入工具参数,声明构建路径的目的;用户要指定源文件及编译数据库文件的路径.

注意,给该工厂成员函数输入两个参数:代表命令行的cl::opt对象的BuildPath对象,及最近声明的ErrorMessage串.

假如引擎加载编译数据库失败了,会用一个消息填充ErrorMessage串,即工厂成员函数没有返回CompilationDatabase对象,这时会马上显示该消息.

llvm::report_fatal_error()函数会触发已配置的任意LLVM错误处理例程,并以1错误码退出工具.它要求包含下面头文件:

#include "llvm/Support/ErrorHandling.h"

示例中,缩写了很多类全名,因此还要在全局域中添加若干个using声明,但是只要你喜欢,也可用全名:

using namespace clang;
using namespace std;
using namespace llvm;
using clang::tooling::RefactoringTool;
using clang::tooling::Replacement;
using clang::tooling::CompilationDatabase;
using clang::tooling::newFrontendActionFactory;

使用AST匹配器

对编写基于Clang的代码重构工具,AST匹配器非常重要.

AST匹配器库让用户可轻松匹配符合特定条件的ClangAST的子树,如,表示所命名为calloc,且有两个参数的函数调用的AST节点.
查找指定的ClangAST节点并修改它们,这是每个代码重构工具共同的基本任务,利用该库,极大地方便了编写此类工具.

为了帮助找到正确的匹配器,依靠ClangQueryAST匹配器文档,文档在此.

先为工具编写叫wildlifesim.cpp的测试案例.这是一个复杂的可沿着直线任意方向遍历的一维动物模拟器:

class Animal {int position;
public:Animal(int pos) : position(pos) {}//返回新位置int walk(int quantity) {return position += quantity;}
};
class Cat : public Animal {
public:Cat(int pos) : Animal(pos) {}void meow() {}void destroySofa() {}bool wildMood() {return true;}
};
int main() {Cat c(50); c.meow();if (c.wildMood())c.destroySofa();c.walk(2);return 0;
}

要求工具可将成员函数比如walk重命名为run.运行ClangQuery,研究此例中的AST.这里用recordDecl匹配器,转存所有表示C结构C++类的RecordDeclAST节点的内容:

$ clang-query wildanimal-sim.cpp --
clang-query> set output dump
clang-query> match recordDecl()
(...)
|-CXXMethodDecl 0x(...) <line:6:3, line 8:3> line 6:7 walk 'int (int)'
(...)

在表示Animal类的RecordDecl对象的内部,观察到按CXXMethodDeclAST节点表示walk.查看AST匹配器文档,发现它由methodDeclAST匹配器匹配.

组合匹配器

AST匹配器的强大在于可组合性.如果只想要声明了叫walk成员函数的MethodDecl节点,可先匹配所有叫walk的命名声明,然后细化匹配同时是方法声明的节点.

hasName("input")匹配器返回所有叫"input"的命名声明.可在ClangQuery中,测试methodDeclhasName的组合:

clang-query> match methodDecl(hasName("walk"))

可见它只返回了一个walk的声明,而不是代码中存在的所有八个不同方法的声明.太好了!

尽管如此,发现仅修改Animal类的walk方法的定义是不够的,因为继承类可能重载它.不想重构工具重写了基类一个方法而不重写继承类中重载方法.

要找到所有定义了walk方法的类,即Animal类或其继承类.为了找到所有Animal类或其继承类,使用期望按NamedDecl参数的isSameOrDerivedFrom()匹配器.

通过带选择所有叫hasName()NamedDecl的匹配器的组合来提供该参数.因此,如下查询:

clang-query> match recordDecl(isSameOrDerivedFrom(hasName("Animal")))

还要选择那些重载walk方法的继承类.hasMethod()断定返回包含指定方法类声明.和第一个查询组合成如下查询:

clang-query> match recordDecl(hasMethod(methodDecl(hasName("walk"))))

为了用and符号语义(满足所有断定)连结两个断定,使用allOf()匹配器.它要求所有传入匹配器必须成立.
此时就可建造最终查询,以找到要重写所有声明:

clang-query> match recordDecl(allOf(hasMethod(methodDecl(hasName("walk"))), isSameOrDerivedFrom(hasName("Animal"))))

用该查询,可精确地找到Animal类或其继承类的所有walk方法的声明.

这样允许修改所有这些声明名字,但是还需要修改方法调用.为此,先观察CXXMemberCallExpr节点和它的memberCallExpr匹配器.试试:

clang-query> match memberCallExpr()

因为代码确实有四个方法调用,ClangQuery返回四个匹配:meow,wildMood,destroySofa,和walk.只对定位最后一个感兴趣.

已知道如何利用hasName()匹配器,来选择指定命名声明,但是如何把命名声明映射到成员函数调用式呢?
答案是用member()匹配器,来只选择命名且和一个方法名字链接声明,然后用callee()匹配器用调用式链接它.

完整式如下:

clang-query> match memberCallExpr(callee(memberExpr(member(hasName("walk")))))

然而,这里,盲目选择了所有调用walk()的方法.这里只想选择那些Animal类或其继承类walk调用.
memberCallExpr()匹配器按参数接受第二个匹配器.会使用thisPointerType()匹配器以仅选择调用对象指定类方法调用.

利用该规则,构建完整表达式:

clang-query>matchmemberCallExpr(callee(memberExpr(member(hasName("walk")))),thisPointerType(recordDecl(isSameOrDerivedFrom(hasName("Animal")))))

在代码中用AST匹配器断定

已决定了用哪些断定来抓正确的AST节点,现在可在工具代码中运用它们了.首先,为了使用AST匹配器,需要添加新的include指令:

#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"

还要添加新的using指令,使得更易引用这些类(在其它指令后面):

using namespace clang::ast_matchers;

第二个头文件,对实际查找机制是必须的.继续编写main函数,开始添加剩余代码:

RefactoringTool Tool(*Compilations, SourcePaths);
ast_matchers::MatchFinder Finder;
ChangeMemberDecl DeclCallback(&Tool.getReplacements());
ChangeMemberCall CallCallback(&Tool.getReplacements()));
Finder.addMatcher(recordDecl(allOf(hasMethod(id("methodDecl", methodDecl(hasName(OriginalMethodName)))), isSameOrDerivedFrom(hasName(ClassName)))), &DeclCallback);
Finder.addMatcher(memberCallExpr(callee(id("member", memberExpr(hasName(OriginalMethodName))))),thisPointerType(recordDecl(isSameOrDerivedFrom(hasName(ClassName)))), &CallCallback);
return Tool.runAndSave(newFrontendActionFactory(&Finder));

3.5版本中,要修改以上代码最后一行

return Tool.runAndSave(newFrontendActionFactory(&Finder).get());

这要就完成了main函数.

第一行代码实例化了个新的RefactoringTool对象.这是用到的LibTooling的需要额外包含语句的第二个类:

#include "clang/Tooling/Refactoring.h"

RefactoringTool类为你的工具实现了协调基本任务的所有逻辑:
打开源文件,解析它们,运行AST匹配器,匹配时调用回调函数,按工具要求修改源码等.

因此,在初化要求对象后,要调用RefactoringTool::runAndSave()结束main函数.

转移控制该类,让它执行所有基本任务.

接着,声明一个已包含其头文件MatchFinder对象.你用ClangQuery练习过的,该类负责匹配ClangAST.
MatchFinder要求用AST匹配器和回调函数配置,提供的AST匹配器匹配一个AST节点时,就会调用回调函数.
回调函数中,可修改源码.按MatchCallback的子类实现回调函数.

接着,声明回调函数对象,并用MatchFinder::addFinder()方法,用回调关联具体的AST匹配器.

声明两个单独回调函数,一个重写方法声明,另一个重写方法调用.这两个回调函数DeclCallbackCallCallback.

把前面设计的两个AST匹配器组合,但是用,用户按命令行参数提供的要重构的类名替换Animal类名.
同样,用也是命令行参数OriginalMethodName替换walk.

战略性地引入了新的叫id()匹配器,它不修改表达式所匹配的节点,只是用具体节点绑定一个名字.为让回调函数可产生替换内容,这很重要.

id()匹配器接受两个参数,第一个是用它取节点节名,第二个是用来抓命名AST匹配器.

第一个AST组合负责定位成员方法声明,命名确定方法的MethodDecl节点.第二个AST组合负责定位调用成员函数,命名与调用成员函数链接CXXMemberExpr节点.

编写回调函数

要定义匹配AST节点时,要执行的动作.为此,创建两个从MatchCallback继承的新类,每个匹配各一个类.

class ChangeMemberDecl : public ast_matchers::MatchFinder::MatchCallback {tooling::Replacements *Replace;
public:ChangeMemberDecl(tooling::Replacements *Replace) : Replace(Replace) {}virtual void run(const ast_matchers::MatchFinder::MatchResult &Result) {const CXXMethodDecl *method = Result.Nodes.getNodeAs<CXXMethodDecl>("methodDecl");Replace->insert(Replacement(*Result.SourceManager, CharSourceRange::getTokenRange(SourceRange(method->getLocation())), NewMethodName));}
};class ChangeMemberCall : public ast_matchers::MatchFinder::MatchCallback {tooling::Replacements *Replace;
public:ChangeMemberCall(tooling::Replacements *Replace) : Replace(Replace) {}virtual void run(const ast_matchers::MatchFinder::MatchResult &Result) {const MemberExpr *member = Result.Nodes.getNodeAs<MemberExpr>("member");Replace->insert(Replacement(*Result.SourceManager, CharSourceRange::getTokenRange(SourceRange(member->getMemberLoc())), NewMethodName));}
};

两个类都私下存储了,只是std::set<Replacement>typedefReplacements对象的引用.Replacement类存储的信息有,用什么文本,在哪个文件的哪些行要打补丁.

RafactoringTool类内部管理Replacement对象集合,因而在main函数中用RefactoringTool::getReplacements()方法取得该集合,并初化回调函数.

用存储它来以后使用的Replacements对象指针定义了个基本构造器.通过重载run()方法,来实现回调的动作,又一次,代码相当简单.

函数按参数接受一个MatchResult对象.对给定匹配,MatchResult类存储了,如id()匹配器请求的按名字绑定的所有节点.

MatchResult对象中可通过节点名公开访问的BoundNodes管理这些节点.因此,在run()函数中的第一个动作是调用特化的BoundNodes::getNodeAs<CXXMethodDecl>方法取感兴趣的节点.

结果,就得到了CXXMethodDeclAST节点的只读版本引用.
访问该节点后,为了决定如何给代码打补丁,需要一个,告诉在源文件中,关联令牌的确切行和列SourceLocation对象.

CXXMethodDecl从表示通用声明的Decl基类(a)继承.它(a)提供了返回想要的SourceLocation对象的Decl::getLocation()方法.

有了它,就可创建第一个Replacement对象,并把它插入工具建议的源码修改列表中.

用到的Replacement构造器需要三个参数:一个SourceManager对象的引用,一个CharSourceRange对象的引用,和包含在头两个参数指定位置要写的新文本串.

SourceManager类是个通用的管理加载内存的源码的Clang组件.CharSourceRange类包含有用的解析器,它分析令牌并推导出组成该令牌的源码区间(文件中的两个点),从而决定要从源码文件中删除的确切符,并为新文本空出位置.

该信息创建新的Replacement对象,并在由RefactoringTool管理的集合存储它,就完成任务了.RefactoringTool应用这些补丁,或去除冲突.

记得在匿名名字空间里,声明所有本地包装,这样避免,翻译单元导出本地符号.

测试你的新重构工具

野生模拟器代码示例,作为测试用例,来测试新创建的工具.现在应该运行make,然后等待LLVM编译并链接你的新工具.

生成工具后,试用一番.看看在命令行接口中,按cl::opt对象声明的参数:

$ izzyrefactor -help

为了使用该工具,还需要编译命令数据库.为了避免创建并运行一个CMake配置文件,手动创建一个.

命名为compile_commands.json,并有如下内容.把<FULLPATHTOFILE>标签替换为野生模拟器源码目录的完整路径:

[
{
"directory": "<FULLPATHTOFILE>",
"command": "/usr/bin/c++ -o wildlifesim.cpp.o -c <FULLPATHTOFILE>/ wildlifesim.cpp",
"file": "<FULLPATHTOFILE>/wildlifesim.cpp"
}
]

保存该编译命令数据库后,就可测试工具了:

$ izzyrefactor -class=Animal -method=walk -newname=run ./ wildfilesim.cpp

现在可检查野生模拟器源码,会看到该工具重命名了所有方法定义和调用.

更多

设置命令数据库的指令.
C++模块
AST匹配器和LibTooling的教程.
ClangTidy的用户手册
ClangFormat的用户手册.
llvm博客

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

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

相关文章

Erlang并发机制 –进程调度

2019独角兽企业重金招聘Python工程师标准>>> Erlang调度器主要完成对Erlang进程的调度&#xff0c;它是Erlang实现软件实时和进程之间公平使用CPU的关键。Erlang运行时&#xff0c;有4种任务需要被调度&#xff1a;进程&#xff0c;Port&#xff0c;Linked-in drive…

Linux 下wifi 驱动开发(二)—— WiFi模块浅析

一、什么是wifi 模块 百度百科上这样定义&#xff1a; Wi-Fi模块又名串口Wi-Fi模块&#xff0c;属于物联网传输层&#xff0c;功能是将串口或TTL电平转为符合Wi-Fi无线网络通信标准的嵌入式模块&#xff0c;内置无线网络协议IEEE802.11b.g.n协议栈以及TCP/IP协议栈。传统的硬件…

VSS2005 上传pdf 空白

加补丁 VS80-KB943847-X86-INTL.exe

Linux 下wifi 驱动开发(一)—— WiFi基础知识解析

一、WiFi相关基础概念 1、什么是wifi 我们看一下百度百科是如何定义的&#xff1a; Wi-Fi是一种可以将个人电脑、手持设备&#xff08;如pad、手机&#xff09;等终端以无线方式互相连接的技术&#xff0c;事实上它是一个高频无线电信号。[1] 无线保真是一个无线网络通信技术…

poj 3348 Cows 求凸包以及凸包的面积

题目来源&#xff1a; http://poj.org/problem?id3348 1:任意多边形p[0,n-1]的面积为 for(int i0 ; i<n-1 ; i){ sum (sk[i]^sk[(i1)%(n) ] )*0.5; } 2: 求凸包&#xff0c; 用graham 模板 代码如下&#xff1a; #include <iostream> #include <algorithm> #in…

Linux 网络设备驱动开发(一) —— linux内核网络分层结构

Linux内核对网络驱动程序使用统一的接口&#xff0c;并且对于网络设备采用面向对象的思想设计。 Linux内核采用分层结构处理网络数据包。分层结构与网络协议的结构匹配&#xff0c;既能简化数据包处理流程&#xff0c;又便于扩展和维护。 一、内核网络结构 在Linux内核中&#…

windows清理剪切板

开始——运行——clipbrd &#xff08;WINR&#xff09;转载于:https://blog.51cto.com/eblog/1390662

Linux 网络设备驱动开发(二) —— Linux 网络栈剖析

一、协议简介 虽然对于网络的正式介绍一般都参考了 OSI&#xff08;Open Systems Interconnection&#xff09;模型&#xff0c;但是本文对 Linux 中基本网络栈的介绍分为四层的 Internet 模型&#xff08;如图 1 所示&#xff09;。 图 1. 网络栈的 Internet 模型 这个栈的最底…

Android之BroadcastReceiver 监听系统广播

绑定广播有两种方式 一.配置文件绑定&#xff0c;在程序未启动也能监听 二.代码方式绑定&#xff0c;在程序启动后才能监听 1.绑定和取消绑定广播 public class MainActivity extends Activity {private Button registerButtonnull;private Button unRegisterButtonnull;privat…

Linux 网络设备驱动开发(三) —— 网络设备驱动基本原理和框架

一、协议栈层次对比 二、Linux网络子系统 Linux网络子系统的顶部是系统调用接口层。它为用户空间提供的应用程序提供了一种访问内核网络子系统的方法&#xff08;socket&#xff09;。位于其下面是一个协议无关层&#xff0c;它提供一种通用的方法来使用传输层协议。然后是具…

国产杀毒软件也开始支持虚拟化

今天不小心看到一个较老的“新”闻&#xff0c;国产安全软件厂商瑞星已经推出支持VMware vshield Endpoint技术的防病毒产品&#xff0c;也就是说如果客户今天使用的是VMware的虚拟化软件&#xff0c;上面运行的所有虚拟机就不需要安装传统的防病毒软件程序&#xff0c;而可以直…

VRP平台基本操作

一、显示系统信息 <Huawei>display version 图上所示可以知道VRP平台信息&#xff0c;运行的版本&#xff0c;运行的时间 二、修改和查看设备系统时间参数 1.查看时间 <Huawei>display clock 2.修改系统日期和时间 三、进入系统视图界面 <Huawei>system-view…

Android中获取应用程序(包)的信息-----PackageManager的使用(一)

本节内容是如何获取Android系统中应用程序的信息&#xff0c;主要包括packagename、label、icon、占用大小等。具体分为两个 部分&#xff0c;计划如下&#xff1a; 第一部分&#xff1a; 获取应用程序的packagename、label、icon等 &#xff1b; 第二部分&#xff1a; 获取应用…

VRP平台总体介绍及基础配置

前言 1、VRP软件系统基础 VRP系统在启动时需要加载“系统软件”和“配置文件”两部分&#xff0c;这与其它品牌网络交换机的操作系统是一样的。如果指定了下次启动的补丁文件&#xff0c;还需加载补丁文件。修改VRP系统启动的场景一般有以下几种&#xff1a; a-- 对交换机进行升…

小强的HTML5移动开发之路(43)——JqueryMobile页眉、工具栏和标签栏导航

一、页眉1、添加页眉和页脚<div data-role"header"><h1>第 1 页</h1></div><div data-role"footer"><h4>页面脚注</h4></div>默认的页眉在屏幕的顶部边缘显示&#xff0c;而且在在屏幕滚动时&#xff0c;…

交换机开发(二)—— 三层交换机报文转发过程

如图所示&#xff0c;假如主机A想访问主机B&#xff0c;首先主机A会将自己的IP地址和子网掩码做与操作,得出网路地址(如:Host-A的IP地址100.1.1.2与自身掩码255.255.255.0做与操作后,得到的网络号是100.1.1.0).然后判断目的IP地址(即Host-B的IP地址)与自己的网络地址是不是在同…

分布式搜索elasticsearch配置文件详解

2019独角兽企业重金招聘Python工程师标准>>> elasticsearch的config文件夹里面有两个配置文件&#xff1a;elasticsearch.yml和logging.yml&#xff0c;第一个是es的基本配置文件&#xff0c;第二个是日志配置文件&#xff0c;es也是使用log4j来记录日志的&#xff…

交换机开发(三)—— 深入分析三层网络交换机的原理和设计

引言传统路由器在网络中起到隔离网络、隔离广播、路由转发以及防火墙的作业&#xff0c;并且随着网络的不断发展&#xff0c;路由器的负荷也在迅速增长。其中一个重要原因是出于安全和管理方便等方面的考虑&#xff0c;VLAN(虚拟局域网)技术在网络中大量应用。VLAN技术可以逻辑…

XML 命名空间(XML Namespaces)

为什么80%的码农都做不了架构师&#xff1f;>>> XML 应用程序 XML CDATA XML 命名空间提供避免元素命名冲突的方法。 命名冲突 在 XML 中&#xff0c;元素名称是由开发者定义的&#xff0c;当两个不同的文档使用相同的元素名时&#xff0c;就会发生命名冲突。 这个…

交换机开发(四)—— ARP 基础知识解析

一、ARP协议简介 Internet是由各种各样的物理网络通过使用诸如路由器之类的设备连接在一起组成的。当主机发送一个数据包到另一台主机的过程中 可能要经过多种不同的物理网络。主机和路由器都是在网络层通过IP地址来识别的&#xff0c;这个地址是在全世界内唯一的。 然而&…