Red Hat9.0学习参考:Linux编程基础_第1页
Red Hat9.0学习参考:Linux编程基础_第2页
Red Hat9.0学习参考:Linux编程基础_第3页
Red Hat9.0学习参考:Linux编程基础_第4页
Red Hat9.0学习参考:Linux编程基础_第5页
已阅读5页,还剩66页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第9章 Linux程序设计基础,本章学习目标 通过对本章的学习,读者应该掌握以下主要内容: Linux编程风格 Linux下IDE的使用 Linux下使用GNU cc开发应用程序 Linux程序的调试 Linux下使用RCS/CVS来管理源程序 Linux下软件打包,9.1 概述,9.1.1 Linux编程 Linux软件开发一直在Internet环境下讲行。这个环境是全球性的,编程人员来自世界各地。只要能够访问Web站点,就可以启动一个以Linux为基础的软件项目。Linux开发工作经常是在Linux用户决定共同完成一个项目时开始的。当开发工作完成后,该软件就被放到Internet站点上,任

2、何用户都可以访问和下载它。由于这个活跃的开发环境,新的以Linux为基础的软件功能日益强大,而且呈现爆炸式的增长态势。 大多数Linux软件是经过自由软件基金会(Free Software Foundation)提供的GNU(GNU 即 GNUs not UNIX)公开认证授权的,因而通常被称作GNU软件。GNU软件免费提供给用户使用,并被证明是非常可靠和高效的。许多流行的Linux实用程序如C编译器、shell和编辑器都是GNU软件应用程序。,Linux程序需要首先转化为低级机器语言即所谓的二进制代码以后,才能被操作系统执行。例如编程时,先用普通的编程语言生成一系列指令,这些指令可被翻译为适

3、当的可执行应用程序的二进制代码。这个翻译过程可由解释器一步步来完成,或者也可以立即由编译器明确地完成。shell编程语言如BASH、TCSH、GAWK、Perl、Tcl和Tk都利用自己的解释器。用这些语言编制的程序尽管是应用程序文件,但可以直接运行。编译器则不同,它将生成一个独立的二进制代码文件然后才可以运行。,9.1.2 Linux编程风格,(1)函数返回类型说明和函数名分两行放置,函数起始字符和函数开头左花括号放到最左边。 (2)尽量不要让两个不同优先级的操作符出现在相同的对齐方式中,应该附加额外的括号使得代码缩进可以表示出嵌套。 (3)按照如下方式排版do-while语句: (4)每个程

4、序都应该以一段简短的说明其功能的注释开头。 (5)请为每个函数书写注释,说明函数是做什么的,需要哪些入口参数,参数可能值的含义和用途。如果用了非常见的、非标准的东西,或者可能导致函数不能工作的任何可能的值,应该进行特殊说明。如果存在重要的返回值,也需要说明。 (6)不要声明多个变量时跨行,每一行都以一个新的声明开头。 (7)当一个if中嵌套了另一个if-else时,应用花括号把if-else括起来。 (8)要在同一个声明中同时说明结构标识和变量或者结构标识和类型定义(typedef)。先定义变量,再使用。,1GNU风格,(9)尽量避免在if的条件中进行赋值。 (10)请在名字中使用下划线以分割

5、单词,尽量使用小写;把大写字母留给宏和枚举常量,以及根据统一惯例使用的前缀。例如,应该使用类似ignore_space_change_flag的名字;不要使用类似iCantReadThis的名字。 (11)用于表明一个命令行选项是否给出的变量应该在选项含义的说明之后,而不是选项字符之后被命名。,2Linux 内核编程风格,(1)Linux内核缩进风格是8个字符。 (2)Linux内核风格采用K return 0; 接下来就要使用 Autoconf 及 Automake 来产生Makefile文件,步骤如下: (1)autoscan 产生一个configure.in的模板,执行 autoscan

6、 后会产生一个configure.scan 的文件,可以用它做为configure.in文件的模板: (2)编辑configure.scan文件,如下所示,并且把文件名改成configure.in (3)执行aclocal和autoconf ,分别会产生 aclocal.m4 及 configure 两个文件: (4)编辑Makefile.am文件,内容如下: (5)执行automake -add-missing ,Automake 会根据 Makefile.am产生一些文件,包含最重要的Makefile.in:,(6)最后执行 ./configure : 现在你的目录下已经产生了一个Make

7、file文件,执行make命令就可以开始编译hello.c 成执行文件,最后执行./hello: # make gcc -DPACKAGE=hello -DVERSION=1.0 -I. -I. -g -O2 -c hello.c gcc -g -O2 -o hello hello.o # ./hello Hello! GNU!,9.4 调试工具GDB,9.4.1 GDB调试器简介,Linux系统中包含了GNU 调试程序gdb,它是一个用来调试C和 C+ 程序的调试器。可以使程序开发者在程序运行时观察程序的内部结构和内存的使用情况。gdb 所提供的一些功能如下所示: 运行程序,设置所有的能影响

8、程序运行的参数和环境; 控制程序在指定的条件下停止运行;,当程序停止时,可以检查程序的状态; 修改程序的错误,并重新运行程序; 动态监视程序中变量的值; 可以单步执行代码,观察程序的运行状态。,gdb的功能非常强大,到目前为止,gdb已能够支持Moduls-2、Chill、Pascal和FORTRAN程序的调试,但是调试这些语言的源程序时有一些功能还不能使用。例如调试FORTRAN程序时还不支持表达式的输入、输出变量或类FORTRAN的词法。 gdb程序调试的对象是可执行文件,而不是程序的源代码文件。然而,并不是所有的可执行文件都可以用gdb调试。如果要让产生的可执行文件可以用来调试,需在执行

9、gcc指令编译程序时,加上-g参数,指定程序在编译时包含调试信息。调试信息包含程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号。gdb 利用这些信息使源代码和机器码相关联。,在命令行上输入gdb并按回车键就可以运行gdb了,如果一切正常的话,将启动gdb,可以在屏幕上看到以下的内容:,GNU gdb Red Hat Linux (5.3post-0.20021129.18rh) Copyright 2003 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public

10、 License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type show copying to see the conditions. There is absolutely no warranty for GDB. Type show warranty for details. This GDB was configured as i386-redhat-linux-gnu. (gdb) 启动gdb后,可以在命令行上指定很多的选项。输入: help

11、 可以获得gdb的帮助信息。如果想要了解某个具体命令(比如break)的帮助信息,在gdb提示符下输入下面的命令: break 屏幕上会显示关于break的帮助信息。从返回的信息可知,break是用于设置断点的命令。另一个获得gdb帮助的方法是浏览gdb的手册页。在Linux Shell提示符输入: man gdb 可以看到man的手册页。,9.4.2 GDB命令的基本使用和应用,1gdb基本命令,还可以用下面的方式来运行gdb: gdb filename 其中,filename是要调试的可执行文件。用这种方式运行gdb可以直接指定想要调试的程序。这和启动gdb后执行file filename

12、命令效果完全一样。也可以用gdb去检查一个因程序异常终止而产生的core文件,或者与一个正在运行的程序相连。 gdb支持很多的命令且能实现不同的功能。这些命令从简单的文件装入到允许你检查所调用的堆栈内容的复杂命令, 下面列出了在使用gdb 调试时会用到的一些命令。 1)file命令:装入想要调试的可执行文件。 2)cd命令:改变工作目录。 3)pwd命令:返回当前工作日录。 4)run命令:执行当前被调试的程序。 5)kill命令:停止正在调试的应用程序。,6)list命令:列出正在调试的应用程序的源代码。 7)break命令:设置断点。 8)Tbreak命令;设置临时断点。它的语法与brea

13、k相同。区别在于用tbreak设置的断点执行一次之后立即消失。 9)watch命令:设置监视点,监视表达式的变化。 10)awatch命令:设置读写监视点。当要监视的表达式被读或写时将应用程序挂起。它的语法与watch命令相同。 11)rwatch命令:设置读监视点,当监视表达式被读时将程序挂起,等侍调试。此命令的语法与watch相同。 12)next命令:执行下一条源代码,但是不进入函数内部。也就是说,将一条函数调用作为一条语句执行。执行这个命令的前提是已经run,开始了代码的执行。 13)step命令:执行下一条源代码,进入函数内部。如果调用了某个函数,会跳到函数所在的代码中等候一步步执行

14、。执行这个命令的前提是已经用run开始执行代码。 14)display命令:在应用程序每次停止运行时显示表达式的值。 15)info break命令:显示当前断点列表,包括每个断点到达的次数。,16)info files命令:显示调试文件的信息。 17)info func命令:显示所有的函数名。 18)info local命令:显示当前函数的所有局部变量的信息。 19)info prog命令:显示调试程序的执行状态。 20)print命令;显示表达式的值。 21)delete命令:删除断点。指定一个断点号码,则删除指定断点。不指定参数则删除所有的断点。 22)Shell命令:执行Linux S

15、hell命令。 23)make命令:不退出gdb而重新编译生成可执行文件。 24)Quit命令:退出gdb。,2gdb应用实例,下面使用gdb调试程序来调试一个实例。被调试的程序相当的简单, 但展示了gdb的典型应用。下面列出了将被调试的程序代码,这个程序被称为greeting.c , 功能是显示一个简单的问候, 再用反序将它列出。,9.5 使用RCS/CVS来管理源代码,9.5.1 RCS的使用,RCS(Revision Control System)即程序改版控制系统,主要功能是用来管理文件的版本,可以节省空间和时间。这样就不需要在每个程序开发到某一个阶段就将数据拷贝到其他的地方备份起来了

16、。 RCS提供了如下几个最重要的指令的: ci指令:将文件放入RCS目录下的控制系统 co指令:从RCS目录下将文件取出 rcs指令:用来对RCS文件进行参数的设置,1基本操作方式,一般而言,RCS所产生出来的文件会放在RCS目录中。所以第一步必须要在当前的目录下制作一个文件: rootwyh linux# mkdir RCS 接下来只要使用ci指令。就可以把文件备份到RCS改版控制系统中: rootwyh linux# ci test.c,若要将文件取出,可以使用下列指令: rootwyh linux# co test.c 取出来的文件是只读文件,若要取出可以写入的工作文件,可以加上-l参数

17、来锁定它: rootwyh linux# co -l test.c 此外将文件放入RCS控制系统时,可以使用-l参数锁定文件,那么目录下的文件依然存在: rootwyh linux# ci -l test.c 若要比较当前的文件和RCS中最新版本的文件,可以使用下列指令: rootwyh linux# rcsdiff test.c,2指定版本,若不指定版本编号时,co会从RCS取得最新的版本。如果要以特定的版本号码写入RCS或读出,可以使用-r参数选项。 rootwyh linux# ci -l -r3.25 test.c -以3.25作为版本编号,rootwyh linux# co -l -

18、r1.2 test.c -将RCS中1.2版的test.c读出 此外,rcsdiff也可以用来指定任何一个版本和当前程序代码进行比较。 rootwyh linux# rcsdiff -r3.25 test.c -取出3.25版与test.c进行比较,3关键词的使用,在RCS中可以将关键词变量放入程序代码中。这些变量经过RCS会变成版本的注解。用户可以将这些关键词说明当作是程序中的批注。 常用的关键词如下: $Author$:将版本放入RCS的用户名称。 $Data$:记录程序代码放入RCS时的日期和时间。 $Header$:记录文件的标头,包括RCS路径名称、版本号码、日期、作者等。,$ID$

19、:和$Header$相同,但不包括RCS路径名称。 $Locker$:记录锁定本版本的用户名称。 $Log$:记录将RCS锁住的时间,所输入的文本语句。 $RCSfiles$:记录RCS文件名称。 $Rivision$:指定版本号码。 $Source$:RCS文件名称,包括其路径。 $State$:使用-s选项所指定的特殊状态。,使用关键词的步骤如下所示: (1)在程序代码中加入任一关键词 rootwyh linux#vi test.c (2)将程序代码放入RCS版本控制系统 rootwyh linux# ci -l test.c (3)将文件再次取出。在取出的过程中,co会将每个关键词展开成

20、其对应的值 rootwyh linux# co -l test.c rootwyh linux# cat test.c,9.5.2 CVS的使用,CVS(Concurrent Version System)是个版本控制系统,利用该系统可以记录源代码文件的历史。例如,当软件修改时会产生Bug,并且可能在做这次修改后很长时间不会发现这些问题。使用CVS就可以容易地回顾老的代码版本去发现哪一次的修改导致这些问题。 如果CVS保留每一次的代码版本,会浪费很多的空间。因此CVS使用一种比较聪明的办法保存多个版本在一个文件中。它仅仅保留版本间的不同内容。如果很多人在同一个项目上工作,则CVS使用让不同开发

21、者独立工作的方式解决了这个问题。每一个开发者的工作都在他自己的目录内,并且CVS将在每个开发者的工作完成后进行合并工作。 在Linux下,CVS的使用一般是以命令行方式。通常,CVS有两种使用方式,一是本机方式,一是远程执行方式。CVS的命令格式是: cvs cvs的选项 cvs的动作 选项 读者可以用cvs H command列出命令command的使用方法。,1开始项目,用CVS管理代码,首先要创建一个“信息仓库”。“信息仓库”简单来说包含一个目录结构。它包括要管理的源代码和用于管理源代码的各种管理文件。,先设置环境变量CVSROOT,指向信息仓库的绝对路径,然后调用CVS的init命令:

22、 # CVSROOT=/usr/local/cvsroot;export CVSROOT # cvs init # ls -l $CVSROOT,2添加项目的文件、目录到信息仓库,要将需要管理的项目的文件加入到信息仓库,并做上标志。如果从头开始一个新的项目,就需要创建一个单独的目录,并把所有要使用的文件做一个有效的组织。而如果在开始使用源文件之前该目录就已经存在,则只需进入该目录就行了。 然后,就可以输入源文件目录: # cvs import -m Create Source Dir cvstest/c wu cvstest,这样会生成 $CVSROOT/cvstest/c 目录。 其中-m用

23、来指定注释信息,如果后面在命令行不指定注释信息,则会启动缺省编辑器(vi)要求输入注释信息;cvstest/c是项目名称(实际上是仓库名,在CVS服务器上会存储在以这个名字命名的仓库里);wu, cvstest分别标识了作者和发行标识。,3命令简介,(1)导出源文件 cvs checkout -r rev-D date-d dir-j merg1 -j merg2 modules -r 导出指定版本的模块 -D 导出指定日期的模块 -d 导出指定目录而不是模块 -j 合并当前版本和指定版本 使用下面的命令会导出刚才生成的模块,并在当前目录下生成与文件仓库中完全一样的目录结构: # cvs ch

24、eckout cvstest/c 对于目录结构比较复杂的模块可以在 $CVSROOT/CVSROOT/modules中加以指定: # cvs checkout CVSROOT/modules 在modules文件中加入下面一行: SOURCE cvstest/c,然后执行: # cvs commit m “Add SOURCE” 以后就可以使用下面的命令在当前路径下生成cvstest/c目录 # cvs checkout SOURCE 在当前路径下生成的这个目录就被称为工作目录,对源文件的所有修改都应该在这个目录下完成,而绝对不允许去改动在文件仓库中$CVSROOT 目录下的文件。,(2)删除

25、、增加、重命名文件和目录 cvs add -k kflags-m message files. -k 指定以后该文件的缺省导出目录 -m 对文件的描述 上述命令会加入一个新的文件到文件仓库里,但直到使用了提交命令它才会真正更新文件仓库。 cvs remove options files 上述命令会从文件仓库中删除文件,但也要到提交之后才有作用。,(3)提交源文件 cvs commit -Rl-m mesg files -R 连子目录一起提交 -l 只提交本地目录(不提交子目录) -m 注释信息 在导出源文件之后,在工作目录中对源文件进行的所有修改都必须在提交之后才能对文件仓库中的源文件起作用,

26、并且新的文件才能够被分配一个新的版本号。 (4)释放工作目录 cvs release d SOURCE 这个命令会删除工作目录 cvstest/c(建议在提交了修改的模块后执行这一步),比使用 rm rf cvstest 要好。,4多用户开发,在多用户的情况下,如果不同用户修改的是同一个文件的不同部分,则使用下面的命令就能进行版本合并(把检出的文件与当前的最新版本合并): # cvs update,(1)冲突解决 在有多个用户对同一个文件进行修改时,如果修改了其中的相同部分,而修改后的内容如果有不同的话,出现冲突是不可避免的。如果在CVS 文件仓库中有一个文件 test.c ,它的版本是1.4

27、,用户A 先检出该文件进行修改,而稍后有用户B检出该文件进行修改,并提前提交成 1.5,而在用户A再提交时就会出现冲突(如果文件内容不同的话),这时CVS会提示需要手工解决。 (2)文件版本管理 cvs log -lR-r rev-d date-w loginfiles -l 不处理子目录 -R 对子目录做同样处理 -r 指定版本号 -d 指定时间 -w 指定登录名 使用上面的命令可以参看当前模块或指定文件的所有历史版本信息。 cvs annotate -lR-r rev|-D date files,-l 不处理子目录 -R 对子目录做同样处理 -r 指定版本号 使用上面的命令可以参看指定文件

28、(检出之后)的所有修改信息。 使用下面的命令可以生成相对于一个指定主版本的分支版本: cvs rtag b r rev_root rev_branch file_name -b 指定生成一个分支版本 -r 指定该分支的主干节点版本号 rev_root 主干版本号 rev_branch 分支版本号 file_name 指定文件,使用“.”表示当前目录下所有文件 使用上面的命令可以生成一个对应版本号的分支版本,由于CVS 版本号是用数字表示的,而且在同一个模块下不同文件的版本完全可能是不同的,所以使用标识会更方便。,例: # cvs rtag b r 1.2 tlb-1 SOURCE 以后要访问该

29、分支版本,可以使用“-r” 选项 # cvs checkout r tlb-1 SOURCE 从当前检出的版本切换到一个分支版本: # cvs update r tlb-1 SOURCE 使用下面的命令可以看版本信息: cvs status vlR files -v 显示所有信息 -l 不显示子目录信息 -R 显示子目录信息 cvs update j rev module 把当前所做的修改与指定版本的文件进行合并。 如果在不同版本之间模块的文件有增减,则可以: # cvs update A # cvs updata jbranch_name,5在远程机器上使用CVS,通过网络使用CVS 有很多

30、种方式,但在这里只介绍比较简单的一种:通过rsh 执行cvs 命令。 1) 在远程机器的.rhosts中加入对本地机的访问许可: tom huang 2) 使用下面的命令检出模块ESMSTRG # cvs d :ext:huangwyhlinux:/work/cvsroot checkout SOURCE 其中,ext 指明了连接方式为 rsh,huang指明了本地用户,wyhlinux指明了远地主机,/work/cvsroot 指明了在远地主机上的$CVSROOT路径,可以在本地设置CVS_SERVER环境变量指明这个目录。,9.6 将软件打包,9.6.1 RPM简介,RPM是Redhat

31、Package Manager的缩写,是由Red Hat公司开发的软件包安装和管理程序,同Windows平台上的Uninstaller和Cleansweep比较类似。使用RPM,用户可以自行安装和管理Linux上的应用程序和系统工具。,RPM可以让用户直接以binary方式安装软件包,并且可替用户查询是否已经安装了有关的库文件;在用RPM删除程序时,会询问用户是否要删除有关的程序。如果使用RPM来升级软件,RPM会保留原先的配置文件,这样用户就不用重新配置新的软件了。RPM保留一个数据库,这个数据库中包含了所有的软件包的资料,通过这个数据库,用户可以进行软件包的查询。RPM虽然是为Linux而

32、设计的,但是已经移值到SunOS、Solaris、AIX、Irix等其它UNIX系统上了。RPM遵循GPL版权协议,用户可以在符合GPL协议的条件下自由使用及传播RPM。 RPM设计的目的有下面几点: 方便的升级功能:RPM让用户不用重新安装整个系统就可以对单个软件包进行升级,当一个新的发行版本问世的时侯,用户也不用重新安装,RPM会替用户全面、自动、智能地升级系统,并且保留用户原先的配置文件,这就大大减少了用户维护系统的工作量。 强大的查询功能:用户可以针对整个软件包的数据,或是某些特定的文件进行查询,也可以轻松地查出其个文件是属于哪个软件包,或是从哪里来的。RPM文件本身是经过压缩的,但用

33、户还是可以很容易地快速查询每个软件包的内容,因为在RPM软件包里,已经加入一些特殊的binary header,记录了全部查询时所需要的数据,这一点大大加快了查询速度。,系统校验:当用户不小心删除了某个重要的文件,但是又不知道是哪些软件包需要这个文件,这时侯就可以用RPM来查询已经安装的软体包中缺了哪些文件,是需否要重新安装。并且用户可以校验出安装的软件包是否已经被别人更改过。 允许用户能够使用“纯净”的源代码:让用户取得“未经处理过的源代码”,同时再附上一份“补丁”程序,用户可凭借这些来完成程序编译工作。这样的做法带来不少好处。例如,如果某个程序的新版本问世了,用户可能没有必要再重头开始做全

34、部的编译工作,先观察“补丁”程序的内容,看看有哪些部分是用户需要做的。这样就能让用户更清楚地知道新版本有哪些改进的地方。 下面简单介绍一下RPM的使用。,1用RPM安装软件包,最简单的安装命令如下: # rpm -ivh xwpe-1.5.29a-1.i386.rpm RPM会输出该软件包的名称,并且显示一个状态条。安装软件很简单,但是有时会给出一些出错消息: Package Alrealy Installed!,表示该软件包已经安装,也可使用-replcepkgs选项强制RPM重新安装这个软件。 Conflicting files 表示该软件包包含某些其他软件包安装过的文件,可加replac

35、epkgs选项覆盖原先的文件。 Unresolved Dependency 表示正确运行该软件需要其他哪些软件包,因为RPM的软件包能够查询该软件的“依赖”关系,所以RPM在安装之前会先查询,如果系统没有安装需要的软件包,就会出现错误提示信息。 但是,如要继续安装,就必须先安装相应的软件包,或使用-nodeps选项强制安装,但不推荐使用,因为这样安装的结果一般不能运行。,2用RPM删除安装软件包,要删除已安装的软件包,只需要执行下面的命令: # rpm -e xwpe,3用RPM升级软件,升级软件类似于安装软件,执行如下命令: # rpm -Uvh xwpe-1.5.31a-1.i386.rp

36、m RPM会自动删除相应软件包的老版本,如果配置文件同新版本不兼容,则会自动将其保存为另一oldconfig.rpmsave文件。这样,用户就可以自已手工去更改相应的配置文件。,4查询软件包,用户可以用RPM q来在RPM的数据库中查询相应的软件,RPM会给出软件包的名称、版本和发布版本号,例如: # rpm -q xwpe xwpe-1.5.29a-1,5用RPM校验软件包,用户可以用RPM来校验已经安装的软件包,RPM可以校验文件大小、MD5校验码、文件权限、类型及属主等信息。,6实际使用技巧,1)可以通过FTP来安装软件包。如果用户能够连上网络,想安装某个新的软件包时,可以直接用它的UR

37、L地址来安装,例如: # rpm I ftp:/ 也可以用网络来查询。 2)假如用户不小心误删了几个文件,但不确定到底是哪些文件,通对整个系统进行校验,以了解哪些部份可能己经损坏,应这样做: # rpm Va 3)如果用户碰到一个认不出来的文件,想要知道是属于哪一个软件包的话,可以这样做: # rpm qf /usr/bin/cdplay 4)如果用户得到一个新的RPM文件,却不清楚它的内容,可以这样做: # rpm -qpi /xwpe-X11-1.5.29a-1.i386.rpm 5)如果用户想了解某个RPM软件包会在系统里安装哪些文件,可以这样做: # rpm -qpl /xwpe-X11-1.5.29a-1.i386.rpm,9.6.2 制作RPM,RPM目前最新的版本4.

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论