個人主頁 : zxctscl
文章封面來自:藝術(shù)家–賢海林
如有轉(zhuǎn)載請先通知
1. 前言
在之前已經(jīng)分享了 【Linux】vim的使用,這次來看看在云服務(wù)器上的編譯器gcc。
2. 初見gcc和g++
我們先寫一段簡單的代碼:
#include<stdio.h>
int main()
{
for(int i=0;i<10;i++)
{
printf("hello: %d\n",i);
}
return 0;
}
當(dāng)我們進(jìn)行編譯的時候:
發(fā)現(xiàn)根本就編譯不了。
這個是因為編譯器版本的問題:
查看編譯器的版本:gcc -v
版本不是最新的,不支持在for里面定義變量。
如果想要支持,那么得加上這個命令:
gcc test.c -std=c99
此時就編過了。
在用gcc時候有一個選項-o,后面接一個名稱,就是把編譯的可執(zhí)行程序再起一個名字:
gcc test.c -o my.exe -std=c99
-o也可以放在前面,但是-o緊跟的就是修改的文件名
gcc -o you.exe test.c -std=c99
在Linux中以.cpp和.cc結(jié)尾的都是c++代碼
寫一個簡單的C++代碼:
#include<iostream>
using namespace std;
int main()
{
for(int i=0;i<10;i++)
{
cout<<"hello linux"<<i<<endl;
}
return 0;
}
在這里編譯這個C++代碼
gcc test.cc
就直接報錯了
所以gcc不能用來編譯c++代碼。
因為gcc是用來編譯C語言的,所以它不認(rèn)識c++的語法。
所以編譯c++代碼得用g++:
g++ test.cc
如果想讓編譯c++代碼時支持更高的特性,可以加上-std=c++11
g++ test.cc -std=c++11
總之:
在編譯C語言時候可以帶上:std=c99
;
在編譯C++代碼時可以帶上:std=c++11
.
那么g++能不能編譯C語言的代碼呢?
g++ test.c
是可以的。
這個也和我們認(rèn)知是一樣的,c++兼容c。
所以g++既能編譯c++,又能編譯C語言。
如果想要編譯一個指定名稱的c++程序,怎么寫呢?
同gcc一樣,加上-o選項,-o后面緊跟著指定的名稱:
g++ -o my.exe test.cc
當(dāng)然-o可以放在前面,也可以放在后面,和gcc的一樣。
g++ test.cc -o you.exe
同樣c++代碼的后綴還有.cpp。
將test.cc先改名為test.cpp:
mv test.cc test.cpp
然后編譯test.cpp,再指向a.out
C++代碼后綴除了.cc和.cpp之外,還有一個.cxx
來直接編譯一下:
g++ test.cxx -o my.exe
那么將后綴改為.txt能行嗎?
mv test.cxx test.txt
這里是不行的,Linux是不關(guān)心文件后綴的,但是編譯器是關(guān)系。這里編譯器就是把.txt當(dāng)成文本文件了。
在之后的博客中都統(tǒng)一將C++后綴為.cc,因為最簡單。
想知道自己對應(yīng)的g++是哪個版本的,就直接用命令:
g++ --version
如果沒有g(shù)++怎么安裝呢?
可以直接在網(wǎng)上搜索,就會出來了
安裝命令就是:
sudo yum install -y gcc-c++
能直接將gcc-c++的標(biāo)準(zhǔn)庫給裝上了。
裝好了,就能直接查看版本:
g++ --version
3. 程序的翻譯過程
程序的翻譯過程:預(yù)處理 編譯 匯編 鏈接
先寫一個簡單的代碼,想看見每個階段的編譯結(jié)果
1 #include<stdio.h>
2 #define M 100
3
4 int main()
5 {
6 for(int i=0;i<10;i++)
7 {
8 printf("hello: %d\n,M:%d",i,M);
9 }
10 printf("hello gcc\n");
11 //printf("hello gcc\n");
12 //printf("hello gcc\n");
13 //printf("hello gcc\n");
14 //printf("hello gcc\n");
15 //printf("hello gcc\n");
16 //printf("hello gcc\n");
17 //printf("hello gcc\n");
18 //printf("hello gcc\n");
19 //printf("hello gcc\n");
20 //printf("hello gcc\n");
21 return 0;
22
23 }
3.1 預(yù)處理
預(yù)處理:要做的是宏替換,去注釋,頭文件展開,條件編譯。
3.1.1 宏替換 去注釋 頭文件展開
-E
就是從現(xiàn)在開始進(jìn)行程序的翻譯,預(yù)處理完成,就停下。
gcc -E test.c -o test.i
進(jìn)入test.i
保存的就是-E后的結(jié)果
將test.c打開,對比發(fā)現(xiàn)test.i有800多行,是怎么來的?
是從test.c的頭文件 #include<stdio.h>
來的。
用來查看C語言標(biāo)準(zhǔn)的頭文件庫:
ls /usr/include/
打開stdio.h發(fā)現(xiàn)有很多函數(shù)聲明
vim /usr/include/stdio.h
再打開test.i
vim test.i
對比一下代碼,發(fā)現(xiàn)宏已經(jīng)替換了,而且注釋了的代碼也不在。
3.1.2 條件編譯
先寫一個代碼在proj.c中:
1 #include<stdio.h>
2 int main()
3 {
4 #ifdef V1
5 printf("功能1\n");
6
7 #elif V2
8 printf("功能1\n");
9 printf("功能2\n");
10 printf("功能3\n");
11
12 #else
13 printf("功能1\n");
14 printf("功能2\n");
15 printf("功能3\n");
16 printf("功能4\n");
17 printf("功能5\n");
18 printf("功能6\n");
19 #endif
20
21 return 0;
22 }
~
在編譯之后打開proj.i
然后用宏定義將V1 定為1:#define V1 1
然后直接編譯:
gcc proj.c
發(fā)現(xiàn)結(jié)果只剩下功能1了。
就行打開proj.c,將#define V1 1
改為#define V2 1
編譯運(yùn)行后:
同樣將v2改為v3.
這個就叫做條件編譯,可以根據(jù)用戶指明的條件,實現(xiàn)代碼的動態(tài)裁剪。
在現(xiàn)實中,可以在軟件維護(hù)一份代碼,用條件編譯的方式,來進(jìn)行代碼的裁剪,這樣就能定制出各種功能的代碼。
把宏刪除。
用-D加上要宏定義的對象和值,再加上宏定義的文件,就可以直接對代碼進(jìn)行宏定義,更方便對代碼進(jìn)行裁剪
gcc -DV1=1 proj.c
也可以裁剪其他的選項。
3.2 編譯
編譯:將C語言變成匯編語言。
-S
:從現(xiàn)在開始進(jìn)行程序的編譯,編譯完成就停下來。
如果想要重新做一遍前面的預(yù)處理再到編譯,那么就用.c文件
gcc -S test.c -o test.s
如果想要從預(yù)處理階段直接編譯就用.i:
gcc -S test.i -o test.s
這里發(fā)現(xiàn)報錯,是因為版本的原因
加上它提示的-std=c99就可以了:
gcc -S test.i -o test.s -std=c99
進(jìn)入test.s看看
vim test.s
發(fā)現(xiàn)里面是匯編語言。
3.3 匯編
匯編:將匯編語言翻譯為二進(jìn)制目標(biāo)文件,這種二進(jìn)制是沒有辦法指向的,還差一個鏈接。
-c
:從現(xiàn)在開始進(jìn)行程序的匯編,匯編完成就停下來。
gcc -c test.s -o test.o
這里的后綴.o,就是.obj,打開之前用vs寫的程序,發(fā)現(xiàn)同樣有。這個文件叫可重定位目標(biāo)文件,不能直接執(zhí)行,形成exe想要用到它。
打開這個test.o文件:
vim test.o
發(fā)現(xiàn)里面形成亂碼:
發(fā)現(xiàn)已經(jīng)是二進(jìn)制文件了:
file test.o
那么能不能直接運(yùn)行呢?
發(fā)現(xiàn)是不行的。
那么給它加上可執(zhí)行的權(quán)限:
發(fā)現(xiàn)還是不能運(yùn)行
一個文件能不能被指向,不止取決于它的權(quán)限,還要本身就是可執(zhí)行程序。
得明白二進(jìn)制目標(biāo)文件是一個臨時文件,是不能夠執(zhí)行的。
3.4 鏈接
鏈接:將二進(jìn)制目標(biāo)文件形成可執(zhí)行程序。
直接:
gcc test.o
就形成可執(zhí)行的目標(biāo)文件了r
當(dāng)然可以加-o帶上形成的程序名:
gcc test.o -o my.exe
就能直接執(zhí)行。
為了方便記憶這些選項,觀察一下可以發(fā)現(xiàn)它們連在一起就是:-ESc,只是E和S要大寫。
后綴就是-iso,就像鏡像文件。
4. 鏈接
鏈接是什么呢?
鏈接是我嗎程序和庫結(jié)合的過程。
語言一定有自己的標(biāo)準(zhǔn)庫,就像c中有c99標(biāo)準(zhǔn),要保證跨平臺性。
ldd
后面接可執(zhí)行程序就會顯示它的動靜態(tài)庫
ldd my.exe
最重要的就是:
查看鏈接到的庫
ls /lib64/libc.so.6 -l
這里就是c標(biāo)準(zhǔn)庫。
我們可以看看這個庫的大?。?/p>
ls /lib64/libc-2.17.so -l
一般進(jìn)行鏈接時是把程序和這個庫鏈接形成一個可執(zhí)行的程序。
這個庫里面在不是庫之前,是C語言標(biāo)準(zhǔn)庫的源代碼,像printf和各種方法,進(jìn)行打包形成這個庫。這個庫的安全性是很高的。
怎么知道庫里面有哪些文件?
會有一批對應(yīng)的頭文件,這個頭文件相當(dāng)于一個方法說明。
所以安裝開發(fā)環(huán)境是:安裝C標(biāo)準(zhǔn)庫和C頭文件
庫分為動態(tài)庫和靜態(tài)庫。在Linux里面有,同樣在windows里面也有。
在在Linux中庫的真正的名字是把前綴lib去掉,去掉“.”后面的后綴。
所以這個就是c標(biāo)準(zhǔn)庫。
因為Linux存在這兩種庫,就決定了,在鏈接時,有兩種方式:動態(tài)鏈接和靜態(tài)鏈接。
4.1 動態(tài)鏈接
舉個例子:就像在學(xué)校旁邊有個網(wǎng)吧,一個學(xué)長(相當(dāng)于編譯器)告訴了小明這個網(wǎng)吧的地址,(就相當(dāng)于有了目標(biāo)庫的地址)這個地址就是,這個過程就是動態(tài)鏈接。
小明在這個網(wǎng)吧(就相當(dāng)于動態(tài)庫)的9號機(jī)(相當(dāng)于庫里面的一個方法,printf),當(dāng)小明在學(xué)校里面作業(yè)(程序執(zhí)行的代碼)想要用到電腦,去了網(wǎng)吧(跳轉(zhuǎn)到庫)的9號機(jī)(想要的方法),用完之后回學(xué)校(返回程序),這個過程就是一次動態(tài)運(yùn)行的過程。
在網(wǎng)吧被派出所查封以后,這個網(wǎng)吧就不能進(jìn)了。也就是說動態(tài)鏈接依賴動態(tài)庫,一旦動態(tài)庫缺失,所有靜態(tài)鏈接,這個庫的程序,都無法執(zhí)行了。
c動態(tài)庫,是默認(rèn)提供的
gcc默認(rèn)形成可執(zhí)行程序,默認(rèn)采用動態(tài)鏈接。
查看文件類型:
file my.exe
使用的是動態(tài)庫鏈接:
動態(tài)庫和動態(tài)鏈接的優(yōu)缺點:
- 不能丟失
- 節(jié)約資源
重新創(chuàng)建一個文件夾,把test.c移動到里面,然后執(zhí)行。
默認(rèn)采用動態(tài)鏈接
4.2 靜態(tài)鏈接
接上個例子:小明在買了網(wǎng)吧9號機(jī)器(庫的方法),這樣每次上網(wǎng)(執(zhí)行程序)都能用,不需要這個網(wǎng)吧了,每次執(zhí)行程序就拷貝到自己的電腦上,這個過程叫靜態(tài)鏈接。這個網(wǎng)吧賣電腦就是靜態(tài)庫。
靜態(tài)鏈接就是:在編譯的時候,把庫中的方法,拷貝到自己的可執(zhí)行程序中。
靜態(tài)庫和靜態(tài)鏈接的優(yōu)缺點:
- 一旦形成,與庫無關(guān)
- 浪費(fèi)資源
形成靜態(tài)鏈接:
gcc -o mytest-static test.c -static -
發(fā)現(xiàn)報錯了:
這個是因為在默認(rèn)情況下,一般靜態(tài)庫都是默認(rèn)沒有安裝的。
安裝命令是:
sudo yum install -y glibc-static libstdc++-static
然后再執(zhí)行:
再ldd看看:
ldd mytest-static
文章來源:http://www.zghlxwxcb.cn/news/detail-838584.html
有問題請指出,大家一起進(jìn)步?。?!文章來源地址http://www.zghlxwxcb.cn/news/detail-838584.html
到了這里,關(guān)于【Linux】編譯器-gcc/g++使用的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!