第6章常用開發(fā)工具(4學(xué)時)_第1頁
第6章常用開發(fā)工具(4學(xué)時)_第2頁
第6章常用開發(fā)工具(4學(xué)時)_第3頁
第6章常用開發(fā)工具(4學(xué)時)_第4頁
第6章常用開發(fā)工具(4學(xué)時)_第5頁
已閱讀5頁,還剩54頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第6章常用開發(fā)工具

6.1概述Linux開發(fā)工作經(jīng)常是在Linux用戶決定共同完成一個項(xiàng)目時開始的。當(dāng)開發(fā)工作完成后,該軟件就被放到Internet站點(diǎn)上,任何用戶都可以訪問和下載它。大多數(shù)Linux軟件是經(jīng)過自由軟件基金會(FreeSoftwareFoundation)提供的GNU(GNU即GNU’snotUNIX)公開認(rèn)證授權(quán)的,因而通常被稱作GNU軟件。GNU軟件免費(fèi)提供給用戶使用,并被證明是非常可靠和高效的。許多流行的Linux實(shí)用程序,如:C編譯器、shell和編輯器都是GNU軟件應(yīng)用程序。6.2gcc編譯系統(tǒng)目前,linux平臺上最常用的是C語言,其編譯系統(tǒng)是gcc,能夠編譯用C,C++等語言編寫的程序。一般來說,系統(tǒng)安裝后就已經(jīng)安裝和設(shè)定好了gcc。在shell的提示符下鍵入gccv,屏幕上就會顯示出目前正在使用的gcc的版本。6.2.1C語言編譯過程C語言程序包括:源文件、頭文件、庫文件;在Linux系統(tǒng)中,C/C++程序編譯命令是gcc;當(dāng)使用gcc時,gcc會完成預(yù)處理、編譯、匯編和連接;前三步生成目標(biāo)文件,連接時把生成的目標(biāo)文件鏈接成可執(zhí)行文件;gcc可以針對不同的源程序文件進(jìn)行不同處理,文件格式以文件的后綴來識別,常見的如表6.1所示。1.預(yù)處理階段預(yù)處理是常規(guī)編譯之前預(yù)先進(jìn)行的工作,故此得名。負(fù)責(zé)讀取C語言源文件,對其中以“#”開頭的指令(偽指令)和特殊符號進(jìn)行處理,如:將“#include”所指出的文件替代該程序行,有兩種格式:

#include<文件名>—預(yù)處理程序在/usr/include目錄下找文件

#include“文件名”

—首先在當(dāng)前工作目錄中找,然后到標(biāo)準(zhǔn)目錄/usr/include中找;

備注:使用gcc命令時設(shè)置選項(xiàng),指定查找頭文件時要優(yōu)先搜索的目錄。對C語言源程序中的宏名進(jìn)行宏替換。

例:#defineEOF-1

預(yù)處理程序?qū)⒊绦蛑杏蠩OF的部分以-1取代。宏定義:1.可以在C程序中:#definenamevalue:如:#definestuname“Wang”2.也可以在gcc命令的選項(xiàng)中設(shè)置宏定義;如:gcc–Dname=definition第二種方式的優(yōu)先級高于第一種方式,可以覆蓋源文件中的定義。預(yù)處理程序?qū)υ闯绦蜻M(jìn)行“替換”之后,輸出的文件就不包含宏定義、文件包含、條件編譯等指令,與源文件功能相同,而形式不同。gcc命令的使用在Linux系統(tǒng)中,C/C++程序編譯命令是gcc,例如:$gcc[options][filenames]其中filenames為所要編譯的程序源文件;執(zhí)行完成后,生成默認(rèn)的可執(zhí)行文件a.out;[options]部分可以有較多取值,如:預(yù)處理選項(xiàng)、編譯選項(xiàng)、優(yōu)化選項(xiàng)、連接選項(xiàng),使得gcc命令的功能很多。【例】gcc預(yù)處理選項(xiàng)$cathello.c#include“test1.h”#definevar1“callforhelp”main(){printf(“display–Dvariable%s\n”,DOPTION);printf(“displayoverwritevar1=%s\n”,var1);printf(“hello,everyone!\n”);}假設(shè)上述程序中,頭文件test1.h存放在目錄/temp中,且頭文件里定義了變量var1,下面用gcc命令對上述C程序進(jìn)行編譯,$gcchello.c則會提示找不到頭文件test1.h,以及DOPTION未定義;

宏定義$gcc–I/temphello.c

因此,編譯的時候要在gcc命令的選項(xiàng)里面,加入頭文件test1.h的路徑:此時,會提示:在gcc命令的選項(xiàng)里加入對DOPTION的宏定義:變量var1重定義、DOPTION未定義$gcc–I/temp–DDOPTION=”test”–Ehello.c

只做預(yù)處理,比如:宏替換,用參數(shù)的取值替代宏名;不做編譯,將結(jié)果顯示在標(biāo)準(zhǔn)輸出上。main(){printf(“display–Dvariable%s\n”,“test”);printf(“displayoverwritevar1=%s\n”,“callforhelp”);printf(“hello,everyone!\n”);}此時,若要用gcc命令編譯并執(zhí)行hello.c程序,則去掉-E選項(xiàng),編譯完成后,生成默認(rèn)的可執(zhí)行文件a.out$a.outdisplay–Dvariabletestdisplayoverwritevar1=callforhelphello,everyone!

2.編譯階段對預(yù)處理之后的輸出文件進(jìn)行詞法分析、語法分析,試圖找出所有不符合語法規(guī)則的部分。并根據(jù)問題給出錯誤消息,終止編譯,或給出警告。當(dāng)確定程序符合語法規(guī)則后,將其“翻譯”為功能等價的中間代碼,或匯編代碼。3.匯編過程匯編程序(Assembler)把匯編代碼翻譯成目標(biāo)機(jī)器代碼;包括代碼段和數(shù)據(jù)段等部分,前者包括程序指令,后者存放各種全局或局部變量。2.gcc的編譯程序選項(xiàng)常用選項(xiàng)及其作用

選項(xiàng)格式功能-c只生成目標(biāo)文件,不進(jìn)行連接。用于對源文件的分別編譯-S只進(jìn)行編譯,不做匯編,生成匯編代碼文件格式,其名與源文件相同,但擴(kuò)展名為.s-ofile

將輸出放在文件file中。如果未使用該選項(xiàng),則可執(zhí)行文件放在a.out中-g指示編譯程序在目標(biāo)代碼中加入供調(diào)試程序gdb使用的附加信息-v在標(biāo)準(zhǔn)出錯輸出上顯示編譯階段所執(zhí)行的命令,即編譯驅(qū)動程序及預(yù)處理程序的版本號$catm1.c#include<stdio.h>main(){intr;printf(“enteraninteger\n”);scanf(“%d”,&r);

square(r);return0;}【例】gcc編譯選項(xiàng)$catm2.c#include<stdio.h>

intsquare(intx){printf(“square=%d\n”,x*x);return(x*x);}若直接編譯m1.c文件:gccm1.c,則會提示:m1.c文件中的main函數(shù)調(diào)用的square函數(shù),但沒有事先定義和聲明。因此需要使用-c選項(xiàng)$gcc–cm1.c$gcc–cm2.c$gccm1.om2.o–om12$m12enteraninteger6square=36

-c選項(xiàng)表示:只生產(chǎn)目標(biāo)文件(后綴為.o,參見表6.1),而不進(jìn)行連接,可用于對源文件分別編譯。4.連接階段連接程序(Linker)要解決外部符號訪問地址問題,即:將一個文件中引用的符號(如:變量、函數(shù)調(diào)用),與該符號在另外一個文件中的定義連接起來,最終成為操作系統(tǒng)可以執(zhí)行的可執(zhí)行文件。6.3gdb程序調(diào)試工具程序中的錯誤可按性質(zhì)分為三種:(1)編譯錯誤,即語法錯誤。在編譯階段出現(xiàn),如:括號不對稱、缺少分號等;(2)運(yùn)行錯誤:運(yùn)行時才能發(fā)現(xiàn),如:除數(shù)為0,循環(huán)終止條件無法達(dá)到。(3)邏輯錯誤:程序可以正常運(yùn)行,但結(jié)果不對。

查找程序中的錯誤,診斷其準(zhǔn)確位置,并予以改正,這就是程序調(diào)試。Linux系統(tǒng)中包含了調(diào)試程序gdb,它是一個用來調(diào)試C和C++程序的調(diào)試器;gdb可以在程序運(yùn)行時觀察程序的內(nèi)部結(jié)構(gòu)和內(nèi)存的使用情況;gdb所提供的一些功能如下所示:運(yùn)行程序,設(shè)置程序運(yùn)行的參數(shù)和環(huán)境;控制程序在指定的條件下停止運(yùn)行;當(dāng)程序停止時,可以檢查程序的狀態(tài);動態(tài)監(jiān)視程序中變量的值;6.3.1啟動gdb和查看內(nèi)部命令gdb程序調(diào)試的對象是可執(zhí)行文件,而不是程序的源代碼文件;如果要讓產(chǎn)生的可執(zhí)行文件可以用來調(diào)試,需在執(zhí)行g(shù)cc指令編譯程序時,加上-g參數(shù),指定程序在編譯時包含調(diào)試信息;(P181,表6.3)并等待用戶輸入相應(yīng)的內(nèi)部命令6.3.2應(yīng)用示例下面的這段程序有錯誤,以其為例,顯示gdb調(diào)試程序的一般情況。宏定義,變量BIGNUM值為1000調(diào)用函數(shù)index_m時,將intary,fltary兩個數(shù)組的首地址,作為參數(shù)傳遞給函數(shù)。理論分析intary數(shù)組分配的內(nèi)存塊fltary數(shù)組分配的內(nèi)存塊內(nèi)存塊大小為100個int型數(shù)據(jù)所占用的空間內(nèi)存塊大小為100個float型數(shù)據(jù)所占用的空間如果進(jìn)行1000次循環(huán)和賦值操作,可能發(fā)生什么情況?傳遞給index_m函數(shù)的是數(shù)組首地址ary數(shù)組分配的內(nèi)存塊fary數(shù)組分配的內(nèi)存塊可能發(fā)生的情況:如果fltary數(shù)組在內(nèi)存中的空間位于intary數(shù)組前面,則:?當(dāng)進(jìn)行到第101次循環(huán),也就是i=100的時候,fary[100]在內(nèi)存中的地址與ary[0]的地址相同!如何通過gdb調(diào)試工具驗(yàn)證上述錯誤?(1)在使用gcc編譯的時候,需要保留一些信息(如:變量的值,數(shù)組的內(nèi)存地址等),才能進(jìn)行g(shù)db調(diào)試:方法如下:使用帶-g選項(xiàng)的gcc命令對該程序進(jìn)行編譯:

$gcc-gdbme.c-odbme

(2)用可執(zhí)行程序文件名dbme作為參數(shù),啟動gdb。

$gdbdbme

即可進(jìn)入gdb環(huán)境如下圖所示初始化完成后,回到gdb提示符狀態(tài)(3)進(jìn)入gdb環(huán)境后,用run命令運(yùn)行該程序,系統(tǒng)給出錯誤提示1.gdb在執(zhí)行過程中,收到系統(tǒng)發(fā)送的SIGSEGV信號,則停止運(yùn)行,表明源程序中出現(xiàn)了段錯誤,即:訪問了錯誤的內(nèi)存段。2.該段錯誤發(fā)生在源文件dbme.c的第19行中,index_m函數(shù)中;并且,gdb給出了兩個數(shù)組ary,fary的基地址,fary數(shù)組的基地址小于ary數(shù)組的基地址。使用backtrace命令,顯示函數(shù)調(diào)用的時,用戶棧的情況。參照源碼中錯誤行的上下文,使用list命令顯示相關(guān)行的內(nèi)容棧底是最初執(zhí)行的函數(shù),即main()函數(shù)棧頂是當(dāng)前正在執(zhí)行的函數(shù),說明執(zhí)行到該函數(shù)時,出現(xiàn)錯誤被停止。List命令不帶參數(shù)時,顯示當(dāng)前行的上下5行,總共10行。用break命令設(shè)置斷點(diǎn),設(shè)置當(dāng)執(zhí)行到某一行時停止運(yùn)行;并且可以結(jié)合step命令,一行行跟蹤程序執(zhí)行過程設(shè)置斷點(diǎn)程序的第19行,且i=100時,程序停止運(yùn)行step命令,每次執(zhí)行一行當(dāng)i=100時,ary[0]的值發(fā)生了錯誤且此時,fary[100]的地址與ary的基地址一樣,發(fā)生了沖突。當(dāng)i=100時,ary[0]的值發(fā)生了錯誤,fary[100]的值是對的另外設(shè)置一個斷點(diǎn),當(dāng)執(zhí)行到第19行時,且i值等于99,停止運(yùn)行此時數(shù)組中的值是正確的。此時數(shù)組中的值是正確的??梢?,數(shù)組的大小與循環(huán)體中變量i的變化范圍有矛盾!100<1000(BIGNUM的值)fary數(shù)組的100號元素占用的內(nèi)存地址,與ary數(shù)組0號元素占用的內(nèi)存地址相同。結(jié)論:準(zhǔn)備工作:為了發(fā)揮gdb的全部功能,需要在編譯源程序時使用-g選項(xiàng):

$gcc-gm1.c-om1

啟動gdb的方法有以下幾種:(1)直接使用shell命令gdb$gdb(2)以一個可執(zhí)行程序作為gdb的參數(shù)$gdbm1

gdb調(diào)試過程中的常用命令歸納與總結(jié)一、顯示源程序和數(shù)據(jù)1.顯示和搜索源程序在被調(diào)試的源程序中,進(jìn)行上下文搜索,也可設(shè)定搜索路徑。(1)顯示源文件利用list命令可以顯示源文件中指定的函數(shù)或代碼行;P186,表6.6(2)模式搜索:在源代碼中搜索給定模式的命令表6.7

forward-searchregexp

searchregexp

reverse-searchregexp

歸納與總結(jié)2.查看運(yùn)行時數(shù)據(jù)

(1)print命令

一般使用格式是:print[/fmt]

exp當(dāng)被調(diào)試的程序停止時,可以用print命令,查看當(dāng)前程序中運(yùn)行的數(shù)據(jù)。如:printiprinti*j(2)gdb所支持的運(yùn)算符①{type}adrexp表示一個數(shù)據(jù)類型為type、存放地址為adrexp的數(shù)據(jù)。②@運(yùn)算符:

printarray@10從基地址array開始的10個數(shù)組元素值printarray[3]@5從array第三個元素開始的,5個數(shù)組元素值③file::var(或者function::var)表示文件file(或者函數(shù)function)中變量var的值歸納與總結(jié)二、控制程序的執(zhí)行進(jìn)入gdb后,可以在源程序的某些行上設(shè)置斷點(diǎn)(breakpoint)程序執(zhí)行到斷點(diǎn)所在行,則暫停執(zhí)行,gdb顯示函數(shù)調(diào)用的蹤跡和變量值;用戶可以根據(jù)需要,自行添加、刪除斷點(diǎn)。此外還有:觀察點(diǎn)(watchpoint):觀察某個表達(dá)式的值是否發(fā)生變化捕捉點(diǎn)(catchpoint):針對程序運(yùn)行時出現(xiàn)的事件,如:進(jìn)程的創(chuàng)建斷點(diǎn)、觀察點(diǎn)、捕捉點(diǎn)統(tǒng)稱為停止點(diǎn)。歸納與總結(jié)1.設(shè)置和顯示斷點(diǎn)

(1)設(shè)置斷點(diǎn):用break命令設(shè)置斷點(diǎn):P190breaklinenum

breaklinenumifcondition

breakfunction

breakfile:linenumbreakfile:function

break*address

break(2)顯示斷點(diǎn):顯示程序中設(shè)置了哪些斷點(diǎn)infobreakpoints[num]infobreak[num]歸納與總結(jié)

維護(hù)停止點(diǎn):清除和停用停止點(diǎn)deletecleardisableenable運(yùn)行程序:設(shè)置斷點(diǎn)后,用run命令運(yùn)行程序歸納與總結(jié)程序的單步跟蹤設(shè)置斷點(diǎn)后,可以讓程序一步步地向下執(zhí)行,用戶可以仔細(xì)檢查運(yùn)行過程,實(shí)行單步跟蹤的命令是step和next,其格式是:

step[N]其中N為步長next[N]

兩者區(qū)別是:后者遇到函數(shù)調(diào)用時,執(zhí)行整個函數(shù),即將其作為一條指令對待;前者進(jìn)入函數(shù)內(nèi)執(zhí)行,每次仍然是執(zhí)行N行語句。歸納與總結(jié)三、其他常用命令1.執(zhí)行shell命令:在gdb環(huán)境中,執(zhí)行Linux的shell命令其格式是:shellcommand-string如:(gdb)shelldate二8月2220:22:48CST2006(gdb)2.修改變量值:用戶根據(jù)需要更改程序運(yùn)行路線、變量的值,如:(gdb)printx=10(gdb)setvariablex=103.跳轉(zhuǎn)執(zhí)行通常,被調(diào)試程序是順序執(zhí)行的,可以利用jump命令,在gdb環(huán)境中讓程序跳轉(zhuǎn)到指定的代碼行。格式為:jumplinenumjump*addr

代碼行的內(nèi)存地址6.3程序維護(hù)工具make

軟件開發(fā)過程中,往往采用結(jié)構(gòu)化的程序設(shè)計(jì)思想,將一個大型程序分為若干個功能明確的子程序;最終的可執(zhí)行文件依賴于各個目標(biāo)文件、源文件、庫文件等,如果其中某些文件修改了,那么是否需要把所有文件都重新編譯、連接一遍呢?為了減輕系統(tǒng)的編譯負(fù)擔(dān),Linux開發(fā)環(huán)境提供了程序維護(hù)工具:make6.3.1make的工作機(jī)制通過使用make工具,程序員只需要定義各文件之間的依賴關(guān)系和相關(guān)操作,make工具自動完成產(chǎn)生新版本的必須操作。其主要功能是:執(zhí)行生成新版本目標(biāo)程序的各個步驟,即:自動檢測一個大型程序的哪些部分需要重新編譯,然后發(fā)出編譯命令?;驹硪褂胢ake命令,必須編寫一個叫做makefile的文件,這個文件描述了軟件包中文件之間的關(guān)系,提供更新每個文件的命令;一般在一個軟件包里,通常是可執(zhí)行文件靠目標(biāo)文件(.o后綴)來更新,目標(biāo)文件靠編譯源文件來更新;makefile寫好之后,每次改變了某些源文件,只要執(zhí)行make命令,所有必要的重新編譯將執(zhí)行。make程序利用makefile中的數(shù)據(jù)、每個文件的最后修改時間來確定那個文件需要更新,對于需要更新的文件,根據(jù)makefile數(shù)據(jù)中定義的命令來更新。是一個文本形式的數(shù)據(jù)庫文件,其中包含一些規(guī)則,告訴make命令需要處理哪些文件,以及如何處理;makefile文件這些規(guī)則主要是描述:“目標(biāo)文件”(不要和編譯時產(chǎn)生的目標(biāo)文件相混淆)是從哪些“相依文件”中產(chǎn)生的,以及用什么命令來執(zhí)行這個產(chǎn)生過程。目標(biāo)文件不一定是最后的可執(zhí)行文件,可以是任何一個中間文件,也可以是其他目標(biāo)文件的依賴文件;在此基礎(chǔ)上,make命令對磁盤上的文件進(jìn)行檢查,如果目標(biāo)文件的生成時間,或改動時間,比它的某個依賴文件還舊的話,make就執(zhí)行相應(yīng)的命令,更新目標(biāo)文件;即:makefile涉及三方面內(nèi)容:目標(biāo)文件、相依文件和操作命令makefile文件示例:假設(shè):某個正在開發(fā)的程序包括prog.c和code.c兩個C語言源文件,頭文件有prog.h和code.h,且:prog.c使用了prog.h和code.h兩個頭文件中聲明的變量;最后生成的可執(zhí)行文件名為test;則,相應(yīng)的makefile文件為:test:prog.ocode.o gcc–otestprog.ocode.o

prog.o:prog.cprog.hcode.h gcc–cprog.c

code.o:code.ccode.h gcc–ccode.c

clean: rm–f*.o目標(biāo)文件位于冒號左邊相依文件位于冒號右邊,通常是編譯目標(biāo)文件所需要的其他文件根據(jù)相依文件,生成目標(biāo)文件,所需執(zhí)行的命令;每個命令占一行,且命令行的起始字符必須為TAB字符。目標(biāo)文件可以是文件名,或者要執(zhí)行的動作:clean是常用的一種專用目標(biāo),用于刪除所有的目標(biāo)模塊。只要文件test的時間戳比文件prog.o或code.o中的任何一個舊,下一行的編譯命令將會被執(zhí)行。在檢查文件prog.o和code.o的時間戳之前,make會在下面的行中尋找以prog.o和code.o為目標(biāo)的規(guī)則;在第三行中找到了關(guān)于prog.o的規(guī)則,該文件的依賴文件是prog.c、prog.h和code.h;同樣,make會在后面的規(guī)則行中繼續(xù)查找這些依賴文件的規(guī)則,如果找不到,則開始檢查這些依賴文件的時間戳,如果這些文件中任何一個的時間戳比prog.o的新,make將執(zhí)行“gcc–cprog.c–oprog.o”命令,更新prog.o文件;make命令對上述規(guī)則的執(zhí)行順序:以同樣的方法,接下來對文件code.o做類似的檢查,依賴文件是code.c和code.h。當(dāng)make執(zhí)行完所有這些套嵌的規(guī)則后,make將處理最頂層的test規(guī)則。如果關(guān)于prog.o和code.o的兩個規(guī)則中的任何一個被執(zhí)行,至少其中一個.o目標(biāo)文件就會比test新,那么就要執(zhí)行test規(guī)則中的命令,將prog.o和code.o連接成目標(biāo)文件test。通過以上的分析過程,可以看到make的優(yōu)點(diǎn):因?yàn)?o文件依賴.c源文件,源碼文件里一個簡單改變都會造成重新編譯,并根據(jù)規(guī)則鏈依次由下到上執(zhí)行編譯過程,直到最終的可執(zhí)行文件被重新連接;例如,當(dāng)改變一個頭文件的時候,由于所有的依賴關(guān)系都在makefile里記錄了,因此,make命令可以自動的重新編譯所有那些因依賴這個頭文件而改變了的源碼文件,如果需要,再進(jìn)行重新連接。Make命令的工作過程如下:①讀入makefile文件;②初始化文件中的變量;③推導(dǎo)隱式規(guī)則,并分析所有規(guī)則;④為所有的目標(biāo)文件創(chuàng)建依賴關(guān)系鏈;⑤根據(jù)依賴關(guān)系和時間數(shù)據(jù),確定哪些目標(biāo)文件要重新生成;⑥執(zhí)行相應(yīng)的生成命令。在默認(rèn)方式下,輸入make命令,就可以調(diào)用它工作:在當(dāng)前目錄下尋找名字為makefile的文件,從第一個規(guī)則開始執(zhí)行。6.3.2使用變量makefile里的變量就像一個環(huán)境變量,一般使用大寫宇母。變量的主要作用如下:保存文件名例如:使用一個變量來保存所有的目標(biāo)文件名,則可以方便地加入新的目標(biāo)文

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論