国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁(yè) > news >正文

淘寶客網(wǎng)站怎么備案新手小白怎么學(xué)做運(yùn)營(yíng)

淘寶客網(wǎng)站怎么備案,新手小白怎么學(xué)做運(yùn)營(yíng),藝術(shù)設(shè)計(jì)專(zhuān)業(yè)學(xué)什么,蘇州網(wǎng)絡(luò)公司代理商目錄 一、編譯器——gcc/g的使用 gcc/g的安裝 gcc的安裝: g的安裝: gcc/g的基本使用 gcc的使用 g的使用 動(dòng)態(tài)鏈接與靜態(tài)鏈接 程序的翻譯過(guò)程 1. 一個(gè)C/C程序的構(gòu)建過(guò)程,程序從源代碼到可執(zhí)行文件必須經(jīng)歷四個(gè)階段 2. 理解選項(xiàng)的含…

目錄

一、編譯器——gcc/g++的使用

gcc/g++的安裝

gcc的安裝:

g++的安裝:

gcc/g++的基本使用

gcc的使用

g++的使用

動(dòng)態(tài)鏈接與靜態(tài)鏈接

程序的翻譯過(guò)程

1. 一個(gè)C/C++程序的構(gòu)建過(guò)程,程序從源代碼到可執(zhí)行文件必須經(jīng)歷四個(gè)階段

2. 理解選項(xiàng)的含義

第一步預(yù)處理:

第二步編譯:?

第三步匯編:?

第四步鏈接:?

動(dòng)靜態(tài)鏈接的認(rèn)識(shí)

驗(yàn)證我們所寫(xiě)的程序是動(dòng)態(tài)鏈接還是靜態(tài)鏈接

file 可執(zhí)行文件

ldd 指令

靜態(tài)庫(kù)的安裝

C語(yǔ)言安裝靜態(tài)庫(kù):

C++安裝靜態(tài)庫(kù):

靜態(tài)鏈接

二、項(xiàng)目自動(dòng)化構(gòu)建工具——make/Makefile

make與Makefile的概念

Makefile的原理

Makefile的語(yǔ)法

依賴(lài)關(guān)系和依賴(lài)方法

項(xiàng)目清理

如何理解 .PHONY 修飾的是一個(gè)偽目標(biāo)

我們可以知道被.PHONY修飾的對(duì)象總可以被執(zhí)行

gcc 如何得知 mytest 是最新呢?

如何證明 gcc 根據(jù)修改的時(shí)間得知 mytest 是最新

Makefile的推導(dǎo)規(guī)則

三、版本控制器——git

git 是什么

git 的操作

1. 進(jìn)入gitte官網(wǎng),先新建一個(gè)倉(cāng)庫(kù)

2、Linux中提交代碼操作

1. git clone拉取遠(yuǎn)端倉(cāng)庫(kù)克隆到本地(目錄克隆到本地)

2. git add .?把需要提交的目錄(項(xiàng)目)復(fù)制或剪切到本地倉(cāng)庫(kù)

3. git commit -m? ‘提交日志’? 修改之后的代碼添加進(jìn)去提交本地庫(kù)

4. git push 推送到遠(yuǎn)程倉(cāng)庫(kù),這才是把本地倉(cāng)庫(kù)的代碼推送至遠(yuǎn)程倉(cāng)庫(kù)

5. 如果在遠(yuǎn)端我們的代碼修改了,git status 查看 git 的狀態(tài)?

6. git log 查看提交歷史記錄

四、調(diào)試器——gdb

調(diào)試之前我們先創(chuàng)建文件以及準(zhǔn)備調(diào)試代碼

test.c 文件

編譯成debug版本

gdb 的使用

gdb的安裝

?編輯

基本使用

① l 查看代碼

② b 打斷點(diǎn)、info查看斷點(diǎn)、d 刪除斷點(diǎn)

③ r 開(kāi)始調(diào)試,調(diào)試起來(lái)

④ n 逐過(guò)程、s 逐語(yǔ)句

⑤ c 運(yùn)行到下一個(gè)斷點(diǎn)處

⑥ bt 查看調(diào)用堆棧

⑦ finish 運(yùn)行完當(dāng)前函數(shù)

⑧ p 查看變量值

⑨ display 常顯示變量的值、undisplay取消常顯示

⑩ until 跳出循環(huán)

? info locals 查看特定區(qū)域的臨時(shí)變量

五、Linux小程序——進(jìn)度條的實(shí)現(xiàn)

基本概念

fflush的使用

回車(chē)換行的理解

倒計(jì)時(shí)程序的實(shí)現(xiàn)

進(jìn)度條的實(shí)現(xiàn)

process.h

process.c

main.c

Makefile


一、編譯器——gcc/g++的使用

gcc/g++的安裝

gcc的安裝:

yum install -y gcc

g++的安裝:

yum install -y gcc-c++ libstdc++-devel

gcc/g++的基本使用

我們?cè)谑褂?gcc/g++ 進(jìn)行編譯的時(shí)候一般都帶選項(xiàng): -o

gcc -o test test.c 這個(gè)命令中,gcc編譯器會(huì)對(duì)test.c這個(gè)源文件進(jìn)行編譯和鏈接操作。正常情況下,如果沒(méi)有-o選項(xiàng),gcc會(huì)生成一個(gè)默認(rèn)名稱(chēng)的可執(zhí)行文件(在 Linux 等系統(tǒng)下通常是a.out)。

但是當(dāng)使用-o test時(shí),編譯器會(huì)將生成的可執(zhí)行文件命名為test,而不是默認(rèn)的a.out。

注意:gcc -o test test.cgcc test.c -o test 這兩種寫(xiě)法都是正確的。在這兩種情況下,gcc編譯器都能夠理解-o test是要將編譯生成的可執(zhí)行文件命名為test,而test.c是要編譯的源文件。

gcc的使用

g++的使用

動(dòng)態(tài)鏈接與靜態(tài)鏈接

我們?cè)趯W(xué)習(xí)動(dòng)態(tài)鏈接與靜態(tài)鏈接的時(shí)候需要對(duì)程序的翻譯過(guò)程進(jìn)行復(fù)習(xí)一下,這都是我們C語(yǔ)言階段就學(xué)習(xí)過(guò)的內(nèi)容。

程序的翻譯過(guò)程

1. 一個(gè)C/C++程序的構(gòu)建過(guò)程,程序從源代碼到可執(zhí)行文件必須經(jīng)歷四個(gè)階段
  • 預(yù)處理:頭文件的展開(kāi)、宏替換、條件編譯、去掉注釋?????
  • 編譯:檢查語(yǔ)法錯(cuò)誤,將預(yù)處理后的源代碼生成為匯編代碼?
  • 匯編:匯編代碼轉(zhuǎn)換成二進(jìn)制的機(jī)器碼???
  • 鏈接:多個(gè)目標(biāo)文件的文件鏈接成一個(gè)可執(zhí)行文件
2. 理解選項(xiàng)的含義

當(dāng)生成了一個(gè)可執(zhí)行文件,但是我們并不想讓他直接編譯完成,編譯的過(guò)程是一下就走完了,而接下來(lái)我們想看他的過(guò)程,就在編譯的時(shí)候帶上選項(xiàng)就可以查看每一個(gè)階段的過(guò)程。

注意:C++同樣是這種過(guò)程。

在測(cè)試之前我們重新在 test.c 中編寫(xiě)一個(gè)用于測(cè)試的代碼?

#include <stdio.h>    
#define N 20    
int main()     
{    //測(cè)試去掉注釋    printf("hello wolrd 1\n");    //printf("hello wolrd 2\n");    //printf("hello wolrd 3\n");    //printf("hello wolrd 4\n");    //printf("hello wolrd 5\n");    //printf("hello wolrd 6\n");    //printf("hello wolrd 7\n");    //printf("hello wolrd 8\n");    //printf("hello wolrd 9\n");    //printf("hello wolrd 10\n");    //測(cè)試條件編譯    
#ifdef CONDITION    printf("condition\n");    
#else    printf("no condition\n");    
#endif       //測(cè)試宏替換    printf("宏:%d\n", N);    return 0;    
} 
第一步預(yù)處理:

選項(xiàng) -E 從現(xiàn)在開(kāi)始,進(jìn)行程序的翻譯,當(dāng)你將預(yù)處理做完,就停下來(lái)。 ?????

如果去掉 –o 預(yù)處理這么多內(nèi)容打印到顯示器上特別不好看,選項(xiàng) -o: 指明形成的臨時(shí)文件名稱(chēng) .i, 使用 .i 作為預(yù)處理文件的擴(kuò)展名是一種比較常見(jiàn)的約定,就像c語(yǔ)言文件名后綴是 .c一樣。

觀察下面的代碼,我們可以看到多了800多行代碼,這就是頭文件的展開(kāi),把庫(kù)中的代碼拷貝過(guò)來(lái)了。

然后就進(jìn)行了宏替換,預(yù)處理階段就已經(jīng)做了的。

最后只剩hello world 1,這就是去掉注釋。

條件編譯這里把這個(gè)沒(méi)有的也裁掉了,這就是條件編譯。

注意:我們要用的頭文件、必須在C語(yǔ)言庫(kù)中存在,平時(shí)在某個(gè)平臺(tái)寫(xiě)代碼的時(shí)候,頭文件必須在該系統(tǒng)中存在 , Linux中庫(kù)頭文件在 /usr/include/stdio.h 目錄下,平時(shí)我們安裝VS2022,同時(shí)也會(huì)把頭文件庫(kù)文件安裝到v2022所對(duì)應(yīng)的目錄下,這也就是我們?yōu)槭裁磳?xiě)代碼可以自動(dòng)補(bǔ)齊的原因。

gcc -E test.c -o test.i

我們不定義CONDITION也可以通過(guò)傳參來(lái)定義?

第二步編譯:?

編譯:把c語(yǔ)言代碼變成匯編代碼。

選項(xiàng) -S:從現(xiàn)在開(kāi)始,進(jìn)行程序的翻譯,做完編譯工作,變成匯編之后,就停下來(lái)。

編譯之后Linux下通常以 .s后綴結(jié)尾作為存儲(chǔ)匯編代碼的文件

gcc -S test.i -o test.s

第三步匯編:?

匯編語(yǔ)言不能被計(jì)算機(jī)直接執(zhí)行,把匯編變成二進(jìn)制目標(biāo)文件

選項(xiàng) -c:將匯編代碼轉(zhuǎn)成二進(jìn)制目標(biāo)文件就停下來(lái),沒(méi)有進(jìn)行鏈接。

vim? test.o 進(jìn)入該文件我們看不懂,但是可以 od test.o進(jìn)行閱讀該二進(jìn)制文件。

test.o雖然是二進(jìn)制文件,但是不能被執(zhí)行,我們可以加上權(quán)限,發(fā)現(xiàn)還是不能被執(zhí)行,原因在于少了一步鏈接,這三個(gè)步驟只在編譯你寫(xiě)的代碼,比如你在c語(yǔ)言上的printf的函數(shù)是你寫(xiě)嗎,你只是調(diào)用了printf,printf的實(shí)現(xiàn)你沒(méi)有寫(xiě)。

gcc -c test.s -o test.o

我們執(zhí)行該目標(biāo)文件發(fā)現(xiàn)不能被執(zhí)行,原因是因?yàn)槿鄙僖徊芥溄?/span>

第四步鏈接:?

我們把前面三個(gè)步驟完成之后就可以進(jìn)行鏈接操作了,鏈接是將多個(gè)目標(biāo)文件以及所需的庫(kù)文件整合在一起的關(guān)鍵過(guò)程。

把你寫(xiě)的代碼和 C標(biāo)準(zhǔn)庫(kù)中的代碼合起來(lái):這就是鏈接的過(guò)程,可以不帶任何選項(xiàng)

gcc test.o –o mytest?

鏈接就形成了可執(zhí)行程序,形成可執(zhí)行的二進(jìn)制程序(庫(kù)+你的代碼)。

gcc test.o -o mytest

動(dòng)靜態(tài)鏈接的認(rèn)識(shí)

我們要明白自己編寫(xiě)的代碼與庫(kù)中的代碼是不同的。像 C 標(biāo)準(zhǔn)庫(kù),是他人事先準(zhǔn)備好以供我們直接使用的。比如我們?cè)诖a里寫(xiě)了像printf這類(lèi)庫(kù)函數(shù)的調(diào)用語(yǔ)句,實(shí)際上我們只是進(jìn)行了調(diào)用,并沒(méi)有去實(shí)現(xiàn)這些函數(shù)。只有在進(jìn)行鏈接這一環(huán)節(jié)時(shí),庫(kù)函數(shù)對(duì)應(yīng)的具體實(shí)現(xiàn)才會(huì)和我們寫(xiě)的代碼關(guān)聯(lián)起來(lái)。

?

而鏈接的本質(zhì),核心就是解決我們調(diào)用庫(kù)函數(shù)時(shí),如何與標(biāo)準(zhǔn)庫(kù)(或其他相關(guān)庫(kù))建立關(guān)聯(lián)的問(wèn)題,這其中就涉及到選擇動(dòng)態(tài)鏈接還是靜態(tài)鏈接的方式。動(dòng)態(tài)鏈接是在程序運(yùn)行時(shí)按需加載共享庫(kù)來(lái)獲取函數(shù)實(shí)現(xiàn),而靜態(tài)鏈接則是在鏈接階段直接把庫(kù)函數(shù)的代碼復(fù)制到可執(zhí)行文件當(dāng)中。

  • 動(dòng)態(tài)鏈接
    • 優(yōu)點(diǎn)
      • 資源節(jié)省:可執(zhí)行程序體積小,因?yàn)椴话瑤?kù)代碼,運(yùn)行時(shí)才加載共享庫(kù),節(jié)省內(nèi)存、磁盤(pán)和網(wǎng)絡(luò)資源。例如多個(gè)程序共享動(dòng)態(tài)庫(kù)內(nèi)存實(shí)例。
      • 更新方便:庫(kù)更新時(shí),只要接口兼容,程序無(wú)需重新編譯就能使用新功能。
    • 缺點(diǎn)
      • 運(yùn)行依賴(lài):依賴(lài)外部環(huán)境,缺少庫(kù)或版本不匹配時(shí)程序無(wú)法運(yùn)行。
      • 性能損耗:啟動(dòng)要加載庫(kù),運(yùn)行中調(diào)用庫(kù)函數(shù)有系統(tǒng)開(kāi)銷(xiāo),影響性能和啟動(dòng)速度。
  • 靜態(tài)鏈接
    • 優(yōu)點(diǎn)
      • 獨(dú)立穩(wěn)定:不依賴(lài)外部庫(kù),庫(kù)升級(jí)、刪除或移動(dòng)不影響程序運(yùn)行,程序有很好的穩(wěn)定性。
      • 行為可預(yù)測(cè):運(yùn)行行為由自身代碼決定,便于在不同環(huán)境部署和調(diào)試。
    • 缺點(diǎn)
      • 資源占用:可執(zhí)行程序體積大,占用更多磁盤(pán)和內(nèi)存空間,多個(gè)程序用相同靜態(tài)庫(kù)會(huì)有代碼冗余。
      • 更新不便:庫(kù)更新時(shí),程序要重新編譯才能使用新功能,大型項(xiàng)目中耗時(shí)耗資源。

動(dòng)靜態(tài)庫(kù)可以類(lèi)比成攝影愛(ài)好者與照片濾鏡庫(kù)

假設(shè)你是一個(gè)攝影愛(ài)好者,你有一部相機(jī)(相當(dāng)于程序本身),你平時(shí)會(huì)拍攝各種各樣的照片(程序執(zhí)行各種任務(wù))。

動(dòng)態(tài)庫(kù)的情況

現(xiàn)在有一個(gè)非常流行的在線照片濾鏡應(yīng)用(相當(dāng)于動(dòng)態(tài)庫(kù))。當(dāng)你拍完照片后,你想要給照片添加一些特殊的濾鏡效果,但是你的相機(jī)本身沒(méi)有這些濾鏡功能(就像程序本身沒(méi)有這個(gè)功能的實(shí)現(xiàn))。

你打開(kāi)相機(jī)中的一個(gè)連接功能(相當(dāng)于程序中的函數(shù)調(diào)用接口),連接到這個(gè)在線濾鏡應(yīng)用。每次你想要使用一個(gè)濾鏡的時(shí)候,相機(jī)就會(huì)通過(guò)網(wǎng)絡(luò)(相當(dāng)于運(yùn)行時(shí)環(huán)境)向這個(gè)在線濾鏡應(yīng)用發(fā)送照片和濾鏡請(qǐng)求(就像程序運(yùn)行時(shí)請(qǐng)求動(dòng)態(tài)庫(kù)中的功能,這就是動(dòng)態(tài)鏈接)。這個(gè)在線濾鏡應(yīng)用會(huì)處理你的照片,添加濾鏡后再把處理后的照片發(fā)送回你的相機(jī)(就像動(dòng)態(tài)庫(kù)提供功能實(shí)現(xiàn)并返回結(jié)果)。

很多攝影愛(ài)好者都可以使用這個(gè)在線濾鏡應(yīng)用(多個(gè)程序共享動(dòng)態(tài)庫(kù))。而且,如果這個(gè)濾鏡應(yīng)用更新了新的濾鏡效果或者優(yōu)化了濾鏡算法(動(dòng)態(tài)庫(kù)更新),只要相機(jī)和濾鏡應(yīng)用之間的連接方式(接口)不變,你的相機(jī)依然可以使用這些新功能來(lái)處理照片。

靜態(tài)庫(kù)的情況

后來(lái),你發(fā)現(xiàn)每次連接到在線濾鏡應(yīng)用很麻煩,而且有時(shí)候網(wǎng)絡(luò)不好就沒(méi)辦法使用濾鏡。于是你購(gòu)買(mǎi)了一個(gè)帶有大量濾鏡功能的存儲(chǔ)卡(相當(dāng)于靜態(tài)庫(kù)),這個(gè)存儲(chǔ)卡可以插入你的相機(jī)。

當(dāng)你把存儲(chǔ)卡插入相機(jī)后,相機(jī)就把存儲(chǔ)卡里的濾鏡功能(就像靜態(tài)庫(kù)中的代碼)復(fù)制到了相機(jī)內(nèi)部的可用功能列表中(就像靜態(tài)鏈接把庫(kù)代碼復(fù)制到可執(zhí)行文件,這就是靜態(tài)鏈接)?,F(xiàn)在你拍攝完照片后,想要添加濾鏡,相機(jī)就可以直接使用存儲(chǔ)卡里已經(jīng)復(fù)制過(guò)來(lái)的濾鏡功能來(lái)處理照片,不需要再連接到外部的在線濾鏡應(yīng)用(不依賴(lài)外部庫(kù)運(yùn)行)。即使這個(gè)在線濾鏡應(yīng)用因?yàn)槟承┰蛲V狗?wù)(比如公司倒閉等情況,就像動(dòng)態(tài)庫(kù)不可用),你依然可以在相機(jī)里使用這些濾鏡功能來(lái)處理照片。

驗(yàn)證我們所寫(xiě)的程序是動(dòng)態(tài)鏈接還是靜態(tài)鏈接
file 可執(zhí)行文件

ldd 指令

ldd? 可執(zhí)行文件 用于查看程序(可執(zhí)行文件或共享庫(kù))依賴(lài)的動(dòng)態(tài)共享庫(kù)的工具。當(dāng)你運(yùn)行ldd命令并跟上一個(gè)可執(zhí)行文件的名稱(chēng)時(shí),它會(huì)顯示該可執(zhí)行文件在運(yùn)行時(shí)需要加載的動(dòng)態(tài)庫(kù)的路徑和名稱(chēng)等相關(guān)信息。

靜態(tài)庫(kù)的安裝

默認(rèn)情況下都是動(dòng)態(tài)鏈接的,如果我們想要靜態(tài)鏈接需要怎么辦呢?

ls? /lib64/libc.a?? 不一定存在靜態(tài)庫(kù),靜態(tài)庫(kù)不存在需要自己安裝。

C語(yǔ)言安裝靜態(tài)庫(kù):
yum install -y glibc-static
C++安裝靜態(tài)庫(kù):
yum install -y libstdc++-static

靜態(tài)鏈接

在系統(tǒng)中,C 動(dòng)態(tài)庫(kù)(也稱(chēng)為共享庫(kù))是被多個(gè)使用該庫(kù)的程序所共享的。盡管使用 C 動(dòng)態(tài)庫(kù)的程序眾多,但通常系統(tǒng)中只存在一份該動(dòng)態(tài)庫(kù)的物理副本。這體現(xiàn)了動(dòng)態(tài)庫(kù)的共享特性,即多個(gè)程序在運(yùn)行時(shí)可以同時(shí)訪問(wèn)并使用這同一個(gè)動(dòng)態(tài)庫(kù),避免了庫(kù)代碼在內(nèi)存中的重復(fù)存儲(chǔ),從而節(jié)省了系統(tǒng)的內(nèi)存資源。例如,標(biāo)準(zhǔn) C 庫(kù)(如libc.so)被眾多的 C 語(yǔ)言程序所依賴(lài),在系統(tǒng)運(yùn)行時(shí),這些程序通過(guò)動(dòng)態(tài)鏈接的方式引用libc.so,而無(wú)需各自擁有一份獨(dú)立的libc.so代碼副本。

靜態(tài)鏈接并不是拷貝動(dòng)態(tài)庫(kù)內(nèi)部的代碼。靜態(tài)鏈接是在程序編譯階段,將所需的庫(kù)代碼(通常是靜態(tài)庫(kù),以.a結(jié)尾)直接復(fù)制到可執(zhí)行文件中,使其成為可執(zhí)行文件的一部分,從而在運(yùn)行時(shí)不再依賴(lài)外部的庫(kù)(包括動(dòng)態(tài)庫(kù))。所以,靜態(tài)鏈接與動(dòng)態(tài)庫(kù)的機(jī)制是相互獨(dú)立的,靜態(tài)鏈接不會(huì)直接操作動(dòng)態(tài)庫(kù)的代碼。

Windows動(dòng)靜態(tài)鏈接的原理是一樣的,動(dòng)態(tài)庫(kù)通常以.dll為后綴,靜態(tài)庫(kù)一般是以.lib為后綴

?我們也可以用C++進(jìn)行靜態(tài)鏈接


二、項(xiàng)目自動(dòng)化構(gòu)建工具——make/Makefile

make與Makefile的概念

make 是一個(gè)命令,Makefile是一個(gè)文件。

make與Makefile存在的意義:

Makefile 所帶來(lái)的好處集中體現(xiàn)在自動(dòng)化編譯方面。這并不意味著完全無(wú)需人工干預(yù),而是在初始階段,開(kāi)發(fā)人員需要根據(jù)項(xiàng)目的結(jié)構(gòu)和需求編寫(xiě) Makefile 文件,精心規(guī)劃好源文件與目標(biāo)文件的依賴(lài)關(guān)系以及相應(yīng)的編譯規(guī)則。一旦 Makefile 文件編寫(xiě)完成,后續(xù)使用 Make 命令時(shí),它會(huì)自動(dòng)讀取 Makefile 中的內(nèi)容,按照既定的規(guī)則和依賴(lài)關(guān)系,有條不紊地對(duì)程序或項(xiàng)目進(jìn)行編譯,無(wú)需開(kāi)發(fā)人員再次手動(dòng)調(diào)整編譯過(guò)程。這使得在項(xiàng)目開(kāi)發(fā)過(guò)程中,無(wú)論是對(duì)單個(gè)源文件進(jìn)行修改后重新編譯,還是對(duì)整個(gè)項(xiàng)目進(jìn)行全新構(gòu)建,都能夠通過(guò)簡(jiǎn)單地執(zhí)行 Make 命令快速、準(zhǔn)確地完成,從而實(shí)現(xiàn)了高效、穩(wěn)定的自動(dòng)化構(gòu)建過(guò)程,為軟件開(kāi)發(fā)的迭代和維護(hù)提供了有力支持。

注意: Makefile的 m 可以大寫(xiě)也可以小寫(xiě)。

我們可以來(lái)使用一下Makefile,下面會(huì)說(shuō)明Makefile

就是不用再手寫(xiě)gcc了,直接make就可以了,看起有點(diǎn)弱,其實(shí)慢慢就會(huì)發(fā)現(xiàn)這個(gè)Makefile很強(qiáng)

Makefile的原理

Makefile 必須包含依賴(lài)關(guān)系和依賴(lài)方法這兩個(gè)關(guān)鍵要素,其存在意義在于為構(gòu)建項(xiàng)目提供自動(dòng)化支持,使項(xiàng)目能夠依據(jù)文件間的依賴(lài)關(guān)系和生成方法,有條不紊地完成編譯、鏈接等構(gòu)建流程,避免手動(dòng)操作的繁瑣與易錯(cuò)性,高效達(dá)成項(xiàng)目構(gòu)建這一目標(biāo)。

Makefile 的運(yùn)行就如同生活中的一個(gè)場(chǎng)景。比如,當(dāng)你打電話說(shuō) “爸,我是你兒子”,此時(shí)這僅僅建立了一種依賴(lài)關(guān)系,即你依賴(lài)于自己的父親,但僅憑這一句,父親并不清楚你到底想要做什么,事情自然無(wú)法推進(jìn),這是因?yàn)槿鄙僖蕾?lài)方法。再比如,你不可能去找室友的爸爸借錢(qián),原因是你和室友的爸爸之間不存在任何依賴(lài)關(guān)系。只有當(dāng)你既明確了依賴(lài)關(guān)系,像打電話跟自己的爸爸表明身份,又清晰地闡述依賴(lài)方法,例如接著說(shuō) “我沒(méi)錢(qián)吃飯了,給我打點(diǎn)錢(qián)吧”,這樣依賴(lài)于父親打錢(qián)這件事情才能夠完成。在 Makefile 中也是如此,只有同時(shí)具備依賴(lài)關(guān)系和依賴(lài)方法這兩個(gè)關(guān)鍵要素,項(xiàng)目構(gòu)建這件事情才能夠順利實(shí)現(xiàn)。

Makefile的語(yǔ)法

依賴(lài)關(guān)系和依賴(lài)方法

第一行整體我們稱(chēng)為:依賴(lài)關(guān)系。
mytest : test.c
目標(biāo)文件(可執(zhí)行程序/臨時(shí)文件) :? 依賴(lài)文件列表, 這里只有一個(gè)依賴(lài)文件
這里表示 mytest? 依賴(lài)于test.c

第二行整體我們稱(chēng)為:依賴(lài)方法

寫(xiě)完了Makefile,我們make一下就會(huì)生成可執(zhí)行文件,然后運(yùn)行該文件就可以了

項(xiàng)目清理

隨著項(xiàng)目的不斷編譯和構(gòu)建,會(huì)產(chǎn)生許多可執(zhí)行程序以及一些諸如目標(biāo)文件(.o文件)、中間編譯文件等臨時(shí)文件。有時(shí)候,我們可能想要重新編譯整個(gè)項(xiàng)目,或者不想保留這些已生成的可執(zhí)行程序和臨時(shí)文件了(比如它們占用了過(guò)多磁盤(pán)空間,或者之前的編譯結(jié)果出現(xiàn)了一些未知問(wèn)題想要重新開(kāi)始等情況),這時(shí)候就需要一種方法來(lái)清理它們。

如何清理:

vim Makefile 進(jìn)入Makefile之后接著往下輸入

clean : 這里可以為空(依賴(lài)關(guān)系可以為空,也就說(shuō)clean不依賴(lài)與任何文件)

在下來(lái) tab 開(kāi)頭的就是依賴(lài)方法

我們?cè)儆?strong> .PHONY 修改 clean

紅色為偽目標(biāo) .PHONY 修飾的是一個(gè)偽目標(biāo)

為什么make 和 make mytest 也是可以,而 clean 要 make clean

第一個(gè)遇到的可以省略名稱(chēng),僅此而已,默認(rèn)情況下只形成一個(gè)目標(biāo)文件(可執(zhí)行目標(biāo)文件),不指名默認(rèn)就是第一個(gè)。

如何理解 .PHONY 修飾的是一個(gè)偽目標(biāo)

當(dāng)我們不斷 make 的時(shí)候,會(huì)發(fā)現(xiàn)不讓你編譯了,因?yàn)槭亲钚碌?#xff0c;沒(méi)有修改沒(méi)必要重新編譯

可是當(dāng)我們?cè)俨粩嗾{(diào)用 make clean 的時(shí)候總是能執(zhí)行 rm –f? mytest

我們可以知道被.PHONY修飾的對(duì)象總可以被執(zhí)行

但是我們一般不會(huì)這樣做,將我們生成的可執(zhí)行程序用.PHONY修飾, 但是這都不是重要的,

最重要的是 gcc 如何得知 mytest 是最新呢???

我們?cè)俑幕卦瓉?lái)的Makefile

gcc 如何得知 mytest 是最新呢?

肯定跟時(shí)間有關(guān)系,在我們學(xué)習(xí)指令的時(shí)候,就接觸過(guò)一個(gè)指令 stat,stat命令是一個(gè)用于查看文件或文件系統(tǒng)狀態(tài)信息的工具。

Access(訪問(wèn)時(shí)間):這是文件最后一次被訪問(wèn)(如查看內(nèi)容)的時(shí)間。

Modify(修改時(shí)間):記錄文件內(nèi)容最后一次修改的時(shí)間。

Change(改變時(shí)間):是文件元數(shù)據(jù)(屬性,如權(quán)限、所有者等)最后一次改變的時(shí)間。

為什么change會(huì)隨著modify的改變而改變呢???

當(dāng)我修改了文件內(nèi)容,modify修改了,change也會(huì)隨著修改,因?yàn)槲募拇笮∽兓?#xff0c;也意味著文件的屬性也跟著變化,所以change會(huì)改變。

Change 和 Modify 的時(shí)間變化能夠理解,但是為什么Access是指我們cat訪問(wèn)/vim查看該文件的時(shí)間,為什么沒(méi)有任何的變化???

訪問(wèn)文件不一定改內(nèi)容,改內(nèi)容一定訪問(wèn),如果每次訪問(wèn)都修改時(shí)間,導(dǎo)致Access修改的頻率太多了,就需要在磁盤(pán)進(jìn)行多次的 IO(輸入 / 輸出)操作,別人設(shè)置文件讓別人閱讀,就不在過(guò)于關(guān)心訪問(wèn)時(shí)間,如果別人修改了文件時(shí)間立馬更新Modify時(shí)間,所以操作系統(tǒng)采用的是你訪問(wèn)次數(shù)達(dá)到多少次就更新一次Access的時(shí)間,這種策略,沒(méi)有什么規(guī)律,我們主要關(guān)注 Change 和 Modify。

我們現(xiàn)在知道了這么多時(shí)間,但是和 gcc 有什么關(guān)系??? 它怎么知道我們文件是最新的????

先有源文件 test.c,再有可執(zhí)行程序 mytest

test.c Modify 的時(shí)間 一定比 mytest Modify 的時(shí)間要更早
如果 test.c 里面有bug改了一下里面的內(nèi)容,然后就會(huì)更新源文件test.c 的 Modify的時(shí)間,這個(gè)時(shí)候,test.c 里面的時(shí)間就是新的,比 mytest 的時(shí)間新了,就是比較兩個(gè)時(shí)間的新舊。

如何證明 gcc 根據(jù)修改的時(shí)間得知 mytest 是最新

我們知道一個(gè)指令touch,除了創(chuàng)建文件還可以修改時(shí)間

touch 可以更新文件的時(shí)間

綜上所述:凡是用.PHONY修飾的就是不要拿時(shí)間作對(duì)比了,你每次都執(zhí)行一下,不要遵守時(shí)間對(duì)比的規(guī)則,每次都要執(zhí)行依賴(lài)方法,而沒(méi)有使用 .PHONY修飾的就是對(duì)比源文件的時(shí)間和可執(zhí)行的時(shí)間變化來(lái)確定是不是需要進(jìn)行編譯。

Makefile的推導(dǎo)規(guī)則

程序的翻譯過(guò)程從預(yù)處理、編譯、匯編、鏈接
文件從 test.i? -> test.s? -> test.o
我們的可執(zhí)行文件 mytest 依賴(lài)于 test.o
而 test.o 依賴(lài)于 test.s
而 test.s 依賴(lài)于test.i

我們?cè)谌粘?xiě)Makefile中我們直接一步到位,直接寫(xiě)依賴(lài)于源文件就可以了。


三、版本控制器——git

今天,就讓我們一起來(lái)學(xué)習(xí)一下個(gè)人使用 git 提交代碼的基本操作流程吧,后續(xù)更復(fù)雜的沖突處理、分支協(xié)作等內(nèi)容我們可以再逐步深入學(xué)習(xí)。

git 是什么

git 就像是一個(gè)超級(jí)智能的代碼 “時(shí)光機(jī)”。假設(shè)你在寫(xiě)代碼,就好像在創(chuàng)作一幅復(fù)雜的畫(huà)作。每次你對(duì)代碼進(jìn)行修改,無(wú)論是添加新功能、修復(fù)小錯(cuò)誤還是優(yōu)化性能,git 都能幫你記錄下這個(gè) “畫(huà)作”(代碼)的不同狀態(tài)。

?

比如說(shuō)你寫(xiě)一個(gè) C++ 程序,最開(kāi)始只有一個(gè)簡(jiǎn)單的打印 “Hello, World!” 的功能,這是你代碼的最初版本,git 就像一個(gè)相冊(cè),把這個(gè)初始版本保存了下來(lái)。之后你添加了一個(gè)計(jì)算兩個(gè)數(shù)字相加的函數(shù),git 又會(huì)把這個(gè)有新功能的版本記錄下來(lái),就好像在相冊(cè)里新增了一張帶有新內(nèi)容的照片,你還可以找到原來(lái)記錄下的版本(可以回顧不同的版本)。

git 的操作

1. 進(jìn)入gitte官網(wǎng),先新建一個(gè)倉(cāng)庫(kù)

?gitte官網(wǎng):Gitee - 基于 Git 的代碼托管和研發(fā)協(xié)作平臺(tái)

?進(jìn)入官網(wǎng)之后我們先創(chuàng)建一個(gè)倉(cāng)庫(kù)

初始化倉(cāng)庫(kù),設(shè)置倉(cāng)庫(kù)模板,選擇分支,我們先這樣進(jìn)行創(chuàng)建,后續(xù)需要深入學(xué)習(xí)git

遠(yuǎn)端就會(huì)形成一個(gè)這個(gè)倉(cāng)庫(kù)?

2、Linux中提交代碼操作

git 的安裝:

sudo yum install -y git

準(zhǔn)備我們要提交的代碼文件

1. git clone拉取遠(yuǎn)端倉(cāng)庫(kù)克隆到本地(目錄克隆到本地)

我們暫時(shí)先使用HTPS,因?yàn)楸容^簡(jiǎn)單如果用SSH,還需要進(jìn)行配置

先復(fù)制好,然后進(jìn)入Linux指令行中輸入 git clone 粘貼剛剛復(fù)制的內(nèi)容

git clone:把遠(yuǎn)端倉(cāng)庫(kù)克隆到本地

當(dāng)我們克隆到本地的時(shí)候,有時(shí)候可能需要輸入自己gitee的賬號(hào)和密碼

Linux中進(jìn)入該倉(cāng)庫(kù),而遠(yuǎn)端隱藏了.git文件

注意點(diǎn): 當(dāng)我們首次安裝好了git之后系統(tǒng)會(huì)提示你進(jìn)行配置 用戶(hù)名 和 郵箱

要將碼云(Gitee)的倉(cāng)庫(kù)與 Linux 系統(tǒng)關(guān)聯(lián)起來(lái)

配置 Git 用戶(hù)名和郵箱(如果還沒(méi)配置的話)---我們?cè)谔峤坏倪^(guò)程中會(huì)出現(xiàn)提示

git config --global user.name "你的gitte用戶(hù)名"git config --global user.email "你的郵箱"
2. git add .?把需要提交的目錄(項(xiàng)目)復(fù)制或剪切到本地倉(cāng)庫(kù)

git add .? 相當(dāng)于添加到臨時(shí)倉(cāng)庫(kù)(還沒(méi)提交到本地庫(kù)),相當(dāng)于一個(gè) "準(zhǔn)備區(qū)"

3. git commit -m? ‘提交日志’? 修改之后的代碼添加進(jìn)去提交本地庫(kù)

git commit -m? ‘提交日志信息’?這個(gè)日志必須寫(xiě),也不要亂寫(xiě)。
這才是提交到了本地倉(cāng)庫(kù) 但是遠(yuǎn)端倉(cāng)庫(kù)還沒(méi)沒(méi)有提交,所以我們需要推送到遠(yuǎn)端倉(cāng)庫(kù)

4. git push 推送到遠(yuǎn)程倉(cāng)庫(kù),這才是把本地倉(cāng)庫(kù)的代碼推送至遠(yuǎn)程倉(cāng)庫(kù)

我們查看遠(yuǎn)端倉(cāng)庫(kù)發(fā)現(xiàn)多了一個(gè)我們提交的文件

5. 如果在遠(yuǎn)端我們的代碼修改了,git status 查看 git 的狀態(tài)?

如果遠(yuǎn)程庫(kù)和本地庫(kù)沒(méi)有同步的話,我們就 git pull 先把遠(yuǎn)端的拉到本地,同步一下,然后再進(jìn)行 push

pull 的本質(zhì)就是強(qiáng)制我們每一個(gè)人必須和遠(yuǎn)端倉(cāng)庫(kù)保持一致,不一致了就pull一下。

git pull 同步遠(yuǎn)程倉(cāng)庫(kù),本地庫(kù)與遠(yuǎn)程倉(cāng)庫(kù)保持一致

如果你本地要?jiǎng)h除這個(gè)文件都在前面加上 git?

6. git log 查看提交歷史記錄


四、調(diào)試器——gdb

  • 在調(diào)試思路上,無(wú)論是在 Windows 還是 Linux 系統(tǒng)下,目的都是為了找出代碼中的錯(cuò)誤。都需要關(guān)注變量的初始化、賦值、變化過(guò)程,檢查函數(shù)的參數(shù)傳遞是否正確、函數(shù)內(nèi)部邏輯是否正確,以及循環(huán)結(jié)構(gòu)是否按照預(yù)期執(zhí)行(如循環(huán)次數(shù)是否正確、循環(huán)體中的邏輯是否正確等)。
  • 比如,在檢查一個(gè)計(jì)算數(shù)組元素總和的函數(shù)時(shí),都需要考慮是否正確地遍歷了數(shù)組,是否正確地累加了元素的值,思路都是從程序的輸入、中間處理過(guò)程到輸出,逐步驗(yàn)證代碼的正確性。

調(diào)試之前我們先創(chuàng)建文件以及準(zhǔn)備調(diào)試代碼

test.c 文件

#include <stdio.h>// 函數(shù)用于統(tǒng)計(jì)給定范圍內(nèi)能被divisor整除的數(shù)的個(gè)數(shù)及它們的和
void countAndSum(int start, int end, int divisor, int *count, int *sum) {*count = 0;*sum = 0;int i = 0;for (i = start; i < end; i++) {  // 這里循環(huán)條件有錯(cuò)誤,少包含了邊界值end,應(yīng)該是i <= end,導(dǎo)致可能少統(tǒng)計(jì)一些數(shù)if (i % divisor == 0) {(*count)++;*sum += i;}}
}int main() {    int start = 1;    int end = 18;int divisor = 3;    int count;    int sum;                                                                                                                       countAndSum(start, end, divisor, &count, &sum);    printf("在 %d 到 %d 范圍內(nèi),能被 %d 整除的數(shù)有 %d 個(gè),它們的和是 %d\n", start, end, divisor, count, sum);    return 0;    
}    

編譯成debug版本

在學(xué)習(xí)C語(yǔ)言的時(shí)候我們就知道編譯存在兩種版本:一種是release發(fā)布版,目的:主要用于向用戶(hù)發(fā)布最終產(chǎn)品,另一種是debug調(diào)試版,目的:專(zhuān)為開(kāi)發(fā)人員在開(kāi)發(fā)和調(diào)試階段使用。

要用 gdb 調(diào)試,變成debug版本才可以調(diào)試,首先要進(jìn)行給編譯條件添加 -g,表示生成debug 版本

gdb 的使用

我們要調(diào)試,直接 gdb 可執(zhí)行程序,發(fā)現(xiàn)我們還沒(méi)有g(shù)db,所以需要安裝

gdb的安裝

sudo yum install -y  gdb

基本使用

① l 查看代碼

l 的全稱(chēng)是 list

l 0 從0行顯示,想再往后顯示不需要輸指令了,直接回車(chē)可以繼續(xù)往下顯示代碼。

② b 打斷點(diǎn)、info查看斷點(diǎn)、d 刪除斷點(diǎn)

打斷點(diǎn):b? 全稱(chēng) breakPoint? b 20 ?? b 23都是打斷點(diǎn)

查看斷點(diǎn): info b

去掉斷點(diǎn):d? 全稱(chēng) deletePoint?? ? d 24這樣刪除不了斷點(diǎn),刪除是刪除斷點(diǎn)編號(hào),添加斷點(diǎn)之后就有了斷點(diǎn)編號(hào)。

③ r 開(kāi)始調(diào)試,調(diào)試起來(lái)

r? 程序跑起來(lái),在斷點(diǎn)處停下來(lái),r? 全稱(chēng)run

r 相當(dāng)于 Visual Studio下的 F5開(kāi)始調(diào)試,VS 下 F5開(kāi)始調(diào)試:有斷點(diǎn)就在斷點(diǎn)處停下來(lái),沒(méi)有斷點(diǎn)就直接跑完了,到另外一個(gè)斷點(diǎn)還是F5。

④ n 逐過(guò)程、s 逐語(yǔ)句

啟動(dòng)調(diào)試之后下一步就可以逐過(guò)程 F10,這里是 n? 全稱(chēng)next 一行一行往下走

想進(jìn)入這個(gè)函數(shù)逐語(yǔ)句 F11,這里是 s? 全稱(chēng) step,可以進(jìn)入某個(gè)函數(shù)

⑤ c 運(yùn)行到下一個(gè)斷點(diǎn)處

c? 全稱(chēng)continue運(yùn)行到下一個(gè)斷點(diǎn)? 可以一直c運(yùn)行到下一個(gè)斷點(diǎn)處

⑥ bt 查看調(diào)用堆棧

s進(jìn)去一個(gè)函數(shù)后, bt 查看函數(shù)的調(diào)用堆棧,出了函數(shù)后還可以繼續(xù)查看調(diào)用堆棧

⑦ finish 運(yùn)行完當(dāng)前函數(shù)

通過(guò)這個(gè)finish可以確定這個(gè)函數(shù)是否存在錯(cuò)誤

⑧ p 查看變量值

p 只能臨時(shí)查看,我們要邊看邊調(diào)試變量的值。

⑨ display 常顯示變量的值、undisplay取消常顯示

常顯示可以顯示變量值和地址,也可以取消變量值和地址,但是取消的時(shí)候也是取消編號(hào)。

取消常顯示

until 跳出循環(huán)

如果問(wèn)題不在循環(huán)里面我們要跳出這個(gè)循環(huán),直接until,然后繼續(xù) n 往下走

? info locals 查看特定區(qū)域的臨時(shí)變量


五、Linux小程序——進(jìn)度條的實(shí)現(xiàn)

基本概念

fflush的使用

這個(gè)代碼會(huì)先出現(xiàn) hello world,然后休眠 2 秒。

如果我們?nèi)サ鬨n就沒(méi)有打印內(nèi)容,兩秒之后內(nèi)容才打印出來(lái),這里先執(zhí)行的是printf,然后執(zhí)行的是sleep,因?yàn)槲覀兊拇a是順序結(jié)構(gòu)。


先執(zhí)行printf不等于數(shù)據(jù)先顯示,printf已經(jīng)執(zhí)行完了,只不過(guò)數(shù)據(jù)在緩沖區(qū)里面,沒(méi)有顯示出來(lái) ,緩沖區(qū)我們不知道是什么,我們目前只需要知道它是一塊內(nèi)存就夠了,如果我們想要這個(gè)內(nèi)容刷新出來(lái),可以使用 fflush(stdout)。

而 \n 刷新的是行緩沖。

fflush(stdout)刷新緩沖區(qū)?

回車(chē)換行的理解

有一組概念回車(chē)換行,回車(chē)換行是兩個(gè)概念,回車(chē)是回到當(dāng)前行的開(kāi)始,換行是換到下一行 ? \r? 回車(chē)?

\n 換行?

\r\n 回車(chē)換行

注意:語(yǔ)言層面 \n 就是回車(chē)換行

倒計(jì)時(shí)程序的實(shí)現(xiàn)

有了這兩個(gè)基礎(chǔ)鋪墊,我們就可以完成一個(gè)簡(jiǎn)單的倒計(jì)時(shí)了。

反斜杠n就是回車(chē)換行,我們不能使用回車(chē)換行,我們就用反斜杠 r

fflush(stdout)刷新緩沖區(qū)?

進(jìn)度條的實(shí)現(xiàn)

有了這些基礎(chǔ)之后,我們實(shí)現(xiàn)這個(gè)進(jìn)度條就很容易上手了。

進(jìn)度條一定是循環(huán)的,頭文件不需要在Makefile中寫(xiě),因?yàn)闀?huì)在源文件中展開(kāi)。

注意點(diǎn):\是C語(yǔ)言中的特殊字符,如果我們要顯示 \ 就需要\\

?????????????? 模上4之后范圍就在0-3

我們先把文件建立好,寫(xiě)好之后先簡(jiǎn)單的測(cè)試一下Makefile是否正確

process.h

#pragma once     
#include <stdio.h>    
#include <unistd.h>    
#include <string.h>    
#define NUM 101    
//#define STYLE '#'    
#define S_NUM 5      
//函數(shù)的聲明                                                                                                              
extern void ProcessOn(); 

process.c

  #include "process.h"    //函數(shù)的實(shí)現(xiàn)void ProcessOn(){int cnt = 0;//字符數(shù)組char bar[NUM];//進(jìn)度條樣式 char STYLE[S_NUM] = {'+','#','@','*','&'};//初始化bar                                                                                                                   memset(bar,'\0',sizeof(bar));//旋轉(zhuǎn)光標(biāo)            const char* lable = "|/-\\";while(cnt <= 100)     {                     //控制格式        printf("[%-100s][%d%%][%c]\r",bar,cnt,lable[cnt%4]);fflush(stdout);   
E>       bar[cnt++] = STYLE[N];                  usleep(50000); //1秒 = 10000毫秒,3秒跑完}                           printf("\n");               }                              

main.c

#include "process.h"                                                                                                               
int main()    
{    ProcessOn();    return  0;    
}    

Makefile

ProcessOn:main.c process.c    gcc main.c process.c -o ProcessOn -DN=1  #-D定義宏                                                                             
.PHONY:clean                                                           
clean:                                                                 rm -rf ProcessOn                                                                   
http://m.aloenet.com.cn/news/42832.html

相關(guān)文章:

  • 企業(yè)網(wǎng)站如何做seo全國(guó)十大跨境電商公司排名
  • 做視頻點(diǎn)播網(wǎng)站要多少帶寬今日重慶重要消息
  • 58這種網(wǎng)站怎么做nba實(shí)力榜最新排名
  • 虎門(mén)專(zhuān)業(yè)網(wǎng)站建設(shè)seo群發(fā)軟件
  • 保定中小企業(yè)網(wǎng)站制作推廣普通話內(nèi)容50字
  • 網(wǎng)站的注冊(cè)和登錄怎么做友情鏈接聯(lián)盟
  • 開(kāi)源快速網(wǎng)站搭建平臺(tái)磁力寶最佳搜索引擎入口
  • wordpress社團(tuán)網(wǎng)站今日頭條最新
  • 視頻網(wǎng)站外鏈怎么做搜什么關(guān)鍵詞比較刺激
  • 西部數(shù)碼網(wǎng)站管理助手4.0 破解版鏈接交易網(wǎng)
  • 簡(jiǎn)單個(gè)人網(wǎng)頁(yè)制作成品手機(jī)優(yōu)化管家
  • 網(wǎng)站建設(shè)外包工作推廣游戲賺錢(qián)的平臺(tái)
  • 招聘企業(yè)網(wǎng)站建設(shè)模塊關(guān)鍵詞排名優(yōu)化是什么意思
  • 南通旅游網(wǎng)站建設(shè)一鍵免費(fèi)建站
  • 搜索網(wǎng)站開(kāi)發(fā)背景廣告留電話號(hào)的網(wǎng)站
  • 目前做批發(fā)比較好的b2b網(wǎng)站百度免費(fèi)發(fā)布信息
  • 創(chuàng)建視頻網(wǎng)站昆明百度搜索排名優(yōu)化
  • 織夢(mèng)高端html5網(wǎng)站建設(shè)工作室網(wǎng)絡(luò)公司網(wǎng)站模板高端營(yíng)銷(xiāo)型網(wǎng)站建設(shè)
  • 信陽(yáng)做網(wǎng)站 漢獅網(wǎng)絡(luò)短視頻seo詢(xún)盤(pán)系統(tǒng)
  • 秦皇島做網(wǎng)站公司win10優(yōu)化大師怎么樣
  • 備案期間怎么做網(wǎng)站磁力
  • 石家莊網(wǎng)站建設(shè)策劃方案杭州seo搜索引擎優(yōu)化
  • 域名停域app免費(fèi)下載上海還能推seo嗎
  • 商城類(lèi)的網(wǎng)站怎么做百度百度一下首頁(yè)
  • 做服裝設(shè)計(jì)兼職的網(wǎng)站短信廣告投放
  • 房地產(chǎn)型網(wǎng)站建設(shè)社區(qū)推廣方法有哪些
  • 做旅游網(wǎng)站官方百度下載安裝
  • 備案用網(wǎng)站建設(shè)方案書(shū)又一病毒來(lái)了比新冠可怕
  • 金華做網(wǎng)站報(bào)價(jià)seo關(guān)鍵字優(yōu)化軟件
  • 免費(fèi)網(wǎng)站建設(shè)作業(yè)總結(jié)seo的作用主要有