![C++编码中减少内存缺陷的方法和工具[转].doc_第1页](http://file.renrendoc.com/FileRoot1/2020-1/14/2286fe09-1584-436b-9203-79659dd9838c/2286fe09-1584-436b-9203-79659dd9838c1.gif)
![C++编码中减少内存缺陷的方法和工具[转].doc_第2页](http://file.renrendoc.com/FileRoot1/2020-1/14/2286fe09-1584-436b-9203-79659dd9838c/2286fe09-1584-436b-9203-79659dd9838c2.gif)
![C++编码中减少内存缺陷的方法和工具[转].doc_第3页](http://file.renrendoc.com/FileRoot1/2020-1/14/2286fe09-1584-436b-9203-79659dd9838c/2286fe09-1584-436b-9203-79659dd9838c3.gif)
![C++编码中减少内存缺陷的方法和工具[转].doc_第4页](http://file.renrendoc.com/FileRoot1/2020-1/14/2286fe09-1584-436b-9203-79659dd9838c/2286fe09-1584-436b-9203-79659dd9838c4.gif)
![C++编码中减少内存缺陷的方法和工具[转].doc_第5页](http://file.renrendoc.com/FileRoot1/2020-1/14/2286fe09-1584-436b-9203-79659dd9838c/2286fe09-1584-436b-9203-79659dd9838c5.gif)
已阅读5页,还剩6页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C+编码中减少内存缺陷的方法和工具程振林,方金云,唐志敏(中国科学院计算技术研究所,北京 100080)摘 要:基于C+的软件的缺陷和错误大部分都和内存相关,预防、发现、消除代码中和内存相关的缺陷,成为程序员编写、调试、维护代码时的重要任务。该文基于“面向网络海量空间信息的大型GIS”课题的工程实践,提出和总结了如何使用C+语言机制、开发环境和相关质量保证工具来预防、发现各种编译期、运行期内存缺陷的方法和工具。关键词:C+;内存错误;内存泄漏;质量保证Techniques and Tools of Defending Memory-related Defects in Software Coded in C+CHENG Zhenlin, FANG Jinyun, TANG Zhimin(Institute of Computing Technology, Chinese Academy of Sciences, Beijing 100080)【Abstract】Most of the defects and errors in the software coded in C+ are memory-related. Based on the practice in the network, large volumespatial information oriented GIS project, this paper presentsthe techniques and tools to find and fix the memory problems during the coding,debugging and production release phase with the support of the C+ language mechanism, development environment and related quality-assurancetools.【Key words】C+; Memory errors; Memory leak; Quality assuranceC+语言是桌面系统,尤其是系统软件、大型应用软件的主流开发语言。C+语言以其灵活性著称,同时也更复杂。利用C+编写健壮的代码,更具有挑战性。C+允许动态内存管理, 同时也容易导致更多和内存相关的问题。一般而言, 除了系统设计上的缺陷, 基于C+的软件的缺陷和错误大部分都和内存缺陷(主要包括内存访问错误和内存泄漏两类)相关。 所以,消除代码中的内存相关缺陷,成为程序员编写、调试、维护代码中的任务,也是保证软件质量的关键。本文的工作基于“863”计划项目“面向网络海量空间信息的大型GIS”课题。该系统是基于C+/MFC编写,开发环境是Visual Studio .net 2003。本文基于此项目的工程实践,总结了如何使用C+语言机制、开发环境和相关质量保证工具来预防、发现各种编译期、运行期和内存相关的缺陷的方法和工具。1 遵循C+相关的编码规范和惯用法,预防缺陷编码规范是语言相关的规则,是经过实践总结出来的经验。良好的编程标准将有效地帮助开发人员避免开发有潜在危险的代码。一般来说,为了减少内存缺陷,应该遵循下列编码规则1:(1)基类或者带有虚函数的类应该将其析构函数声明为虚函数。(2)在构造函数中防止内存泄漏,在析构函数中不要抛出异常。(3)使用对应形式的new和delete。即:用delete来释放new申请的内存,delete释放new申请的内存。(4)指针在使用前必须初始化,指向动态内存的指针在释放后应立即置为空。(5)如果类构造函数中分配了资源,那么需要显式提供拷贝构造函数和赋值操作符,并且在析构函数中释放资源。值得重视的是C+中的惯用法RAII。RAII核心思想是利用对象来管理资源,在对象的构造函数中获取资源,在其析构函数中释放资源2。为了保证动态申请的内存能在即使出现异常的情况下仍能释放,比较理想的方法是使用局部变量来管理动态内存的所有权(ownership),就是所谓的智能指针。STL中的auto_ptr就是为解决资源所有权问题设计的,但是缺少对引用数和数组的支持并且不能用在STL容器中。Boost库3提供的智能指针相对成熟,实用价值高。其中,shared_ptr线程安全并且可以用在STL容器中。具体示例参考文献3。1.1 编码规范检查工具 CodeWizardCodeWizard能够对源程序直接进行自动扫描、分析和检查。一旦发现违例,产生信息告知与哪条规则不符并作出解释。以CodeWizard 4.3 为例,其中内置了超过500条编码标准。CodeWizard可以选择对于当前的工程执行哪些编码标准。CodeWizard可以和VC+紧密集成,安装完毕以后,VC+中有CodeWizard工具条。1.2 代码检查工具 PC-LintPC-Lint可检查编译器不易发现的错误。PC-Lint可对100多个C库函数进行检查,可以发现标准C/C+代码中的1 000多个常见错误。要把PC-lint和Visual Studio集成在一起,需要自己配置。Jon Zyzyck提供了一个报告生成器,可以帮助完成这个工作。可在下载。文献4说明了如何在VC+环境中集成PC-Lint。2 利用语言机制、开发环境和相关工具以预防和发现内存缺陷发现问题是解决问题的前提。相对于修复内存缺陷,发现内存缺陷并准确定位导致缺陷的代码更为费时费力。及早准确地发现内存缺陷,对于提高开发效率非常重要。2.1 利用断言及早暴露内存缺陷断言是布尔调试语句,用来检测在程序运行的时候某一条件的值是否总为真。断言经常用来确认函数的输入、输出,检查对象的当前状态是否合法等。 在以下的场景使用断言可以帮助发现和内存非法访问相关的错误:(1)验证指针是否可读/写。在函数的入口处,经常需要验证指针所指向的内容区域是否可读/写。 通常采用assert(p!= NULL)的检测形式。 但是,指针的值不为空并不代表指针指向了合法可读/写内存。Win32 API提供了函数IsBadReadPtr、IsBadWritePtr、IsBadStringPtr、IsBadCodePtr用来检测指针指向的内存区域是否可读/写。C运行时库提供了_CrtIs ValidPointer、_CrtIsValidHeapPointer等函数,MFC库提供了AfxIsValidAddress、AfxIsValidString函数来完成类似功能。(2)对基于MFC的程序,ASSERT_VALID宏通过调用重载的AssertValid函数来确定指向CObject派生类对象的指针是否有效。ASSERT_VALID宏主要调用了AfxIsValidAddress函数和CObject派生类对象的AssertValid函数(参考MFC源代码afx.h、objcore.cpp)。2.2 利用C运行时刻库检查内存泄漏VC+的C运行库(CRT)提供了广泛的功能,帮助用户检测内存泄漏。CRT提供了_CrtMemCheckPoint、_CrtDump MemoryLeaks、_CrtSetDbgFlag等函数来帮助调试内存泄漏。对于非MFC的工程, 要开启有效的内存泄漏报告功能, 需要进行如下设置:(1)在StdAfx.h的头部添加如下代码并开启编译器/Yu 选项: #define _CRTDBG_MAP_ALLOC #include #include #define DEBUG_NEW new(_NORMAL_BLOCK, THIS_FILE, _LINE_)(2)确保在每个.cpp文件的头部包含以下内容: #include stdafx.h #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE = _FILE_; #endif(3)在程序的开始处开启报告内存泄漏的开关:_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);对于MFC工程, MFC已经做了相关的工作, 只需要确认在每个.cpp文件的头部包含上述第(2)点的内容。在某些情况下,需要知道发生内存泄漏的内存块中的内容,但是标准的内存转储只是内存块头部的十六进制形式。为了得到更多的有用信息,需要以用户块类型(_CLIENT_ BLOCK)申请内存,并利用_CrtSetDumpClient建立用户块型内存的转储函数。具体的说,对于不是从CObject继承的类,需要:(1)为每个类/结构指定一个用户块子类型(参考crtdbg.h)。(2)在申请内存时,采用重载的new形式:void* _cdecl operator new(size_t nSize, int nType, LPCSTR lpszFileName, int nLine)(参考MFC源代码 afxmem.cpp),其中nType就是用户块的子类型。(3)创建一个用户块内存转储函数,专门对每种需要转储的子类型进行处理(需要包含dbgint.h)。(4)利用_CrtSetDumpClient对用户块内存转储函数进行注册(参考MFC源代码dumpinit.cpp)。对于从CObject继承来的类,MFC 已经按照上述方法做了基础工作(参考MFC源代码 afxmem.cpp、dumpinit.cpp)。要有效转储从CObject继承的对象,需要:(1)对每个从CObject继承的类重载虚函数Dump。(2)在程序的初始化部分 加入代码 afxDump.SetDepth(1)来开启深度转储。2.3 利用Purify和Insure+查找运行时内存缺陷Rational Purify和Parasoft Insure+ 是用于运行时错误检查的工具。Purify主要检测:数组内存越界读/写,使用未初始化的内存,对已释放的内存进行读/写,内存泄漏等。Insure+利用其专利技术(源码插装和运行时指针跟踪)能够发现大量的内存操作错误,报告错误的源代码行和执行轨迹。根据笔者的测试(基于98个有各种内存错误的C+程序,涵盖了典型情形),Insure+ 6.1都能准确检测。3 利用VC+环境的调试和诊断功能,检查和发现常见内存缺陷理解常见的内存缺陷问题以及在VC+环境下的症状,能辅助我们减少问题的发生和及时修改问题。从错误的表现形式上看, 和堆栈有关的错误主要分为两大类:堆栈溢出和函数返回信息被破坏。(1)堆栈溢出(overflow)此类错误主要有两种情形:1)过大的局部变量。缺省情况下Windows为每个线程保留1M堆栈空间。在菜单Project-Properties-Configuration Properties - Linker-System中可以看到Stack Reserve Size选项可以调整保留的堆栈空间大小。2)递归调用层数过深。在调试过程中,调用堆栈(call stack)窗口中可以发现函数递归调用的模式。(2)函数返回信息被破坏此类错误主要有两种情形:1)对局部变量的写操作超出了范围(上溢)。在调试过程中,函数堆栈被破坏掉的明显标志是无法显示调用堆栈,并且错误发生在被调用函数即将返回的位置。2)在调用函数和被调用函数之间如果出现了函数参数的不匹配或者调用规范的不一致。为了检查此类错误,应该在代码编译时打开/GS、/RTCs开关(在菜单Project-Properties-Configuration Properties- C/C+-Code Generation下设置)。另外一类错误是动态内存错误。典型的情况如下:(1)内存写越界。在调试版本中,如果是写上溢,就会收到“Damage:after block.”的跟踪消息,如果是写下溢出就会收到“Damage: before block.”的跟踪消息。(2)删除不合法指针。在调试版本中,删除未初始化的指针或者非堆指针时,会收到_CrtIsValidHeapPointer断言错误。(3)多次释放。在调试版本中,如果多次删除同一指针, 会收到_BLOCK_TYPE_IS_VALID断言错误。要防止此类错误,应在delete某个指向动态内存的指针后立即将其置为空。4 利用Windows结构化异常处理机制处理发布版本软件的内存崩溃在程序的发布阶段,应尽量减少程序错误尤其是内存崩溃。如果崩溃了,应该“优雅”地退出,尽量收集程序崩溃时的运行信息以帮助程序供应商后续的调试。要捕捉内存非法访问并获知非法访问的指令地址、寄存器内容等信息,需要用到Windows的结构化异常处理(Structured Exception Handling,SEH)机制6。MiniDumpWriteDump是dbghelp.dll提供的一个 API函数(参考MSDN),用于转储用户模式程序的一些信息(比如堆栈情况等)并存为一个文件(比如.dmp文件),此文件可以被微软的调试器(VC+或者WinDBG)利用进行事后调试。使用此函数需要dbghelp.h、dbghelp.lib和dbghelp.dll(这些文件可以在Windows Platform SDK中找到)。要事后根据.dmp文件调试代码,需要为发布版本软件产生debug symbols (pdb)文件(打开编译器/DEBUG选项)。在拿到.dmp文件以后,用VC+打开.dmp文件,然后调试执行(按F5键)。这样,崩溃现场就会重现。文献5基于上述的方法实现了崩溃报告系统。5 结论实践证明,在上述方法和工具支持下的减少软件内存缺陷的方法和工具,可以有效防止和查找代码中的内存错误和内存泄漏,并且能和开发人员日常编码无缝结合,执行起来非常高效。上述方法配合单元测试、代码评审、每日构建、Bug追踪等措施,形成了一个高效的质量保证流程,在我们的大型平台软件开发过程中起到了重要作用。参考文献1 Sutter H, Alexandrescu A. C+ Coding Standards: 101 Rules, Guidelines, and Best PracticesM. Addison-Wesley Professional, 2004-10.2 Stroustrup B. The Design and Evolution of C+M. Addison-Wesley Professional, 1994-03.3 Karlsson B. Beyond the C+ Standard Library: An Introduction to BoostM. Addison-Wesley Professional, 2005-08.4 Zyzyck J. A Report Generator for PC-LintJ. Dr. Dobbs Journal, 2003, 28(2): 52.5 Dietrich H. XCrash Report: Exception Handling and Crash ReportingZ. 2003-10. /debug/ XCrash ReportPt4.asp.6 Richter J M. Programming Applications for Microsoft WindowsM. Microsoft Press, 1999-09.C/C+ 编程语言的最强大功能之一便是其动态分配和释放内存,但是中国有句古话:“最大的长处也可能成为最大的弱点”,那么 C/C+ 应用程序正好印证了这句话。在 C/C+ 应用程序开发过程中,动态分配的内存处理不当是最常见的问题。其中,最难捉摸也最难检测的错误之一就是内存泄漏,即未能正确释放以前分配的内存的错误。偶尔发生的少量内存泄漏可能不会引起我们的注意,但泄漏大量内存的程序或泄漏日益增多的程序可能会表现出各种 各样的征兆:从性能不良(并且逐渐降低)到内存完全耗尽。更糟的是,泄漏的程序可能会用掉太多内存,导致另外一个程序垮掉,而使用户无从查找问题的真正根源。此外,即使无害的内存泄漏也可能殃及池鱼。幸运的是,Visual Studio 调试器和 C 运行时 (CRT) 库为我们提供了检测和识别内存泄漏的有效方法。下面请和我一起分享收获如何使用 CRT 调试功能来检测内存泄漏?一、如何启用内存泄漏检测机制VC+ IDE 的默认状态是没有启用内存泄漏检测机制的,也就是说即使某段代码有内存泄漏,调试会话的 Output 窗口的 Debug 页不会输出有关内存泄漏信息。你必须设定两个最基本的机关来启用内存泄漏检测机制。一是使用调试堆函数:#define _CRTDBG_MAP_ALLOC #include #include注意:#include 语句的顺序。如果更改此顺序,所使用的函数可能无法正确工作。通过包含 crtdbg.h 头文件,可以将 malloc 和 free 函数映射到其“调试”版本 _malloc_dbg 和 _free_dbg,这些函数会跟踪内存分配和释放。此映射只在调试(Debug)版本(也就是要定义 _DEBUG)中有效。发行版本(Release)使用普通的 malloc 和 free 函数。#define 语句将 CRT 堆函数的基础版本映射到对应的“调试”版本。该语句不是必须的,但如果没有该语句,那么有关内存泄漏的信息会不全。二是在需要检测内存泄漏的地方添加下面这条语句来输出内存泄漏信息:_CrtDumpMemoryLeaks();当在调试器下运行程序时,_CrtDumpMemoryLeaks 将在 Output 窗口的 Debug 页中显示内存泄漏信息。比如: Detected memory leaks!Dumping objects -C:Tempmemleakmemleak.cpp(15) : 45 normal block at 0x00441BA0, 2 bytes long.Data: 41 42c:program filesmicrosoft visual studiovc98includecrtdbg.h(552) : 44 normal block at 0x00441BD0, 33 bytes long.Data: 00 43 00 CD CD CD CD CD CD CD CD CD CD CD CD CDc:program filesmicrosoft visual studiovc98includecrtdbg.h(552) : 43 normal block at 0x00441C20, 40 bytes long.Data: 08 02 43 00 16 00 00 00 00 00 00 00 00 00 00 00Object dump complete.如果不使用 #define _CRTDBG_MAP_ALLOC 语句,内存泄漏的输出是这样的:Detected memory leaks!Dumping objects -45 normal block at 0x00441BA0, 2 bytes long.Data: 41 42 44 normal block at 0x00441BD0, 33 bytes long.Data: 00 43 00 CD CD CD CD CD CD CD CD CD CD CD CD CD 43 normal block at 0x00441C20, 40 bytes long.Data: C0 01 43 00 16 00 00 00 00 00 00 00 00 00 00 00 Object dump complete.根据这段输出信息,你无法知道在哪个源程序文件里发生了内存泄漏。下面我们来研究一下输出信息的格式。第一行和第二行没有什么可说的,从第三行开始:xx:花括弧内的数字是内存分配序号,本文例子中是 45,44,43;block:内存块的类型,常用的有三种:normal(普通)、client(客户端)或 CRT(运行时);本文例子中是:normal block; 用十六进制格式表示的内存位置,如:at 0x00441BA0 等;以字节为单位表示的内存块的大小,如:32 bytes long; 前 16 字节的内容(也是用十六进制格式表示),如:Data: 41 42 等;仔细观察不难发现,如果定义了 _CRTDBG_MAP_ALLOC ,那么在内存分配序号前面还会显示在其中分配泄漏内存的文件名,以及文件名后括号中的数字表示发生泄漏的代码行号,比如: C:Tempmemleakmemleak.cpp(15)双击 Output 窗口中此文件名所在的输出行,便可跳到源程序文件分配该内存的代码行(也可以选中该行,然后按 F4,效果一样) ,这样一来我们就很容易定位内存泄漏是在哪里发生的了,因此,_CRTDBG_MAP_ALLOC 的作用显而易见。使用 _CrtSetDbgFlag如果程序只有一个出口,那么调用 _CrtDumpMemoryLeaks 的位置是很容易选择的。但是,如果程序可能会在多个地方退出该怎么办呢?在每一个可能的出口处调用 _CrtDumpMemoryLeaks 肯定是不可取的,那么这时可以在程序开始处包含下面的调用:_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );这条语句无论程序在什么地方退出都会自动调用 _CrtDumpMemoryLeaks。注意:这里必须同时设置两个位域标志:_CRTDBG_ALLOC_MEM_DF 和 _CRTDBG_LEAK_CHECK_DF。设置 CRT 报告模式默认情况下,_CrtDumpMemoryLeaks 将内存泄漏信息 dump 到 Output 窗口的 Debug 页, 如果你想将这个输出定向到别的地方,可以使用 _CrtSetReportMode 进行重置。如果你使用某个库,它可能将输出定向到另一位置。此时,只要使用以下语句将输出位置设回 Output 窗口即可:_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );有关使用 _CrtSetReportMode 的详细信息,请参考 MSDN 库关于 _CrtSetReportMode 的描述。二、解释内存块类型前面已经说过,内存泄漏报告中把每一块泄漏的内存分为 normal(普通块)、client(客户端块)和 CRT 块。事实上,需要留心和注意的也就是 normal 和 client,即普通块和客户端块。1.normal block(普通块):这是由你的程序分配的内存。2.client block(客户块):这是一种特殊类型的内存块,专门用于 MFC 程序中需要析构函数的对象。MFC new 操作符视具体情况既可以为所创建的对象建立普通块,也可以为之建立客户块。3.CRT block(CRT 块):是由 C RunTime Library 供自己使用而分配的内存块。由 CRT 库自己来管理这些内存的分配与释放,我们一般不会在内存泄漏报告中发现 CRT 内存泄漏,除非程序发生了严重的错误(例如 CRT 库崩溃)。 除了上述的类型外,还有下面这两种类型的内存块,它们不会出现在内存泄漏报告中:1.free block(空闲块):已经被释放(free)的内存块。 2.Ignore block(忽略块):这是程序员显式声明过不要在内存泄漏报告中出现的内存块三、如何在内存分配序号处设置断点在内存泄漏报告中,的文件名和行号可告诉分配泄漏的内存的代码位置,但仅仅依赖这些信息来了解完整的泄漏原因是不够的。因为一个程序在运行时,一段分配内存的代码可能会被调用很多次,只要有一次调用后没有释放内存就会导致内存泄漏。为了确定是哪些内存没有被释放,不仅要知道泄漏的内存是在哪里分配的,还要知道泄漏产生的条件。这时内存分配序号就显得特别有用这个序号就是文件名和行号之后的花括弧里的那个数字。 例如,在本文例子代码的输出信息中,“45”是内存分配序号,意思是泄漏的内存是你程序中分配的第四十五个内存块:Detected memory leaks!Dumping objects -C:Tempmemleakmemleak.cpp(15) : 45 normal block at 0x00441BA0, 2 bytes long.Data: 41 42 .Object dump complete.CRT 库对程序运行期间分配的所有内存块进行计数,包括由 CRT 库自己分配的内存和其它库(如 MFC)分配的内存。因此,分配序号为 N 的对象即为程序中分配的第 N 个对象,但不一定是代码分配的第 N 个对象。(大多数情况下并非如此。)这样的话,你便可以利用分配序号在分配内存的位置设置一个断点。方法是在程序起始附近设置一个位置断点。当程序在该点中断时,可以从 QuickWatch(快速监视)对话框或 Watch(监视)窗口设置一个内存分配断点:例如,在 Watch 窗口中,在 Name 栏键入下面的表达式:_crtBreakAlloc如果要使用 CRT 库的多线程 DLL 版本(/MD 选项),那么必须包含上下文操作符,像这样: ,msvcrtd.dll_crtBreakAlloc现在按下回车键,调试器将计算该值并把结果放入 Value 栏。如果没有在内存分配点设置任何断点,该值将为 1。用你想要在其位置中断的内存分配的分配序号替换 Value 栏中的值。例如输入 45。这样就会在分配序号为 45 的地方中断。 在所感兴趣的内存分配处设置断点后,可以继续调试。这时,运行程序时一定要小心,要保证内存块分配的顺序不会改变。当程序在指定的内存分配处中断时,可以查看 Call Stack(调用堆栈)窗口和其它调试器信息以确定分配内存时的情况。如果必要,可以从该点继续执行程序,以查看对象发生了什么情况,或许可以确定未正确释放对象的原因。尽管通常在调试器中设置内存分配断点更方便,但如果愿意,也可在代码中设置这些断点。为了在代码中设置一个内存分配断点,可
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 海宁活动策划服务方案价格(3篇)
- 装修现场吊顶施工方案(3篇)
- 养殖业合作发展及产品质量保障合同
- 天津的春节作文400字作文400字(7篇)
- 关于青春的中考话题作文7篇
- 童话寓言作文漂亮的小兔贝贝700字14篇
- 时间时刻课件
- 农业资源开发使用权出让合同
- 一年级日记等车150字9篇范文
- 农业经济管理责任与目标达成合同书
- 水利工程设计变更表格
- 上海交通大学学生生存手册
- 收益还原法课件
- 执业风险与棘手医患纠纷防范与处理
- 《抽象函数》 教学课件
- 西藏民主改革60周年模板课件
- DBJ50∕T-342-2019 工程建设对既有建(构)筑物安全影响评估标准
- NBT-4701焊接工艺评定中英文格式-填写范本-20
- 人教版高中化学教材必修1解读
- 远洋航线设计、航法及气象导航
- 内部审计常用表格文书
评论
0/150
提交评论