CentOS 7 之Helloworld with c


其實我也不知道是為了啥, 到了現在這種年紀還想學習Linux下的C語言編程。因為我一直就傻傻地認為機會是垂青有准備的人,也一直呆呆地認為活到老學到老。現在Android這么火,各種終端如雨后春筍,而這些終端如果不安裝Windows的,勢必會使用開源的Linux,而Linux上面跑的程序,C還是占據很大市場的,一旦時機成熟,就可以立馬換車改門庭,不至於產生職業耽誤。這就是我的這種蠢蠢的初衷。在深圳,特別是現在這個時段,周圍的人想到的是如何快速的融入股市,殺進房金融市場,趁着牛市的尾巴賺個盆滿缽滿,買房買車,迎娶白富美,實現人生的偉大理想。我這種想法似乎十分幼稚,但此時此刻,當我發布這篇隨筆時,我的的確確就是這么想的。

回到今天的主題,我今天是想先通過一個簡單的Hello,World的程序,然后講講Module,講講Makefile 等一些非常初級的c編程,如果你很熟悉Linux和C的話,那么你可以選擇繞過這篇,或者你可以在后面發表你的建議,歡迎批評指正,但拒絕一上來就亂噴的青子,我們都過了那個年齡了。

首先來看一下我使用的gcc版本

cc -v

 或者

gcc -v

http://images.cnblogs.com/cnblogs_com/SLKnate/628534/o_gccVersion.png

至於為什么兩個命令得到的是相同的信息gcc version 4.8.3 20140911 (Red Hat 4.8.3-9) (GCC)呢? 這是因為cc是unix下的編譯器,而現在大多數的linux上,都把cc連接到gcc。也就是說cc是gcc的軟連接。

 

1,  開始我們的第一個程序代碼編寫吧,這里我使用的編輯器是vim 

vim hello.c

然后在hello.c里輸入

#include <stdio.h>

int main(int argc, char* argv[])
{
    prinftf("Hello,World!");    
    return 0;   
}

  :wq!出來之后,繼續輸入

gcc hello.c -o hello.out && ./hello.out

就這么簡單,就可以得到我們偉大的Hello, World程序了。

 http://images.cnblogs.com/cnblogs_com/SLKnate/628534/o_helloworld.png

這里我只是補充說明一下上面如果不使用-o hello.out來指定輸出的文件名的話,那么gcc會默認生成一個叫a.out的文件出來。那么后面的連接的就應該相應的改成a.out了,也就是

gcc hello.c && ./a.out

當然,如果你覺得這個&& 突兀的冒出來,一時不知是干什么用的話,那么你也可以分成兩批去執行,先編譯,然后再執行。其實&&的作用就是將兩個命令合在一起提交,如果前一個命令如果沒有返回錯誤的話,那么繼續執行下一條命令。上面的語句就是編譯完hello.c沒有錯誤的話,緊接着就執行剛編譯出來的程序。對於我來說,我是喜歡用&&來聯接的,我在網上下載下來的源程序也常喜歡make && make install來一步執行。因為我覺得./configure 沒有錯的話,后面基本上沒有啥大問題了,當然這不是絕對。 

 

2, 偉大的Hello,World就完成了。之所以偉大,就是因為其極其簡單,武俠小說里面常常也說簡單就是實用,比如楊過練的獨孤九劍,使用的劍是要比平常人的寶劍要重得的多的,謂之曰重劍不鋒。但是一直靠大砍大殺的簡單招式去對敵的話,估計也成就不了神雕大俠的。所以還有獨孤九式,還有黯然銷魂掌等等,所以接下來,我們也來把hello.c改變一點點,注意是一點點,仍然很簡單,就是我們讓hello.c里的main方法去調用另一個方法。

#include <stdio.h>

int main(int argc, char* argv[])
{
    int a=33;
    int b=22;
    int maxNo=max(a,b);
    printf("the max number is %d",maxNo);  
    return 0;   
}

int max(int a, int b)
{
    if(a>b) return a;
    return b;
}

嗯,上面這段代碼最終輸出:

the max number is 33.

按照我們的意願得到了結果,這是一個很好的開端。但是我們想想,如果這個max函數是由別人來協同開發的,兩個人不可能都來修改hello.c這個文件吧?如果是那樣的話就亂套了,merge 的時候都會把人搞瘋的。為了不瘋人,為了少抓狂,我們把max這個函數另存進一個max.c文件里去,或者由另一位同事去實現。

這里我講一下我的操作是這樣子的。

vim hello.c

打開編輯,然后再把光標移到int max(int a,intb)的那一行,按5dd得到5行到剪貼板,然后:sp max.c,然后ctrol+w+上光標鍵,最后按p,將復制的那5行碼貼入max.c里,最后:wqa!

分開了兩個文件之后,我們的編譯就得這樣了:

gcc max.c hello.c -o hello.out

 最后執行

./hello.out

也可以得到想要的正確結果。 

the max number is 33.

 

3, 嗯,很好,完成了分離了,結果如預期所想。完美解決方案。可是不久之后,又有人實現了一個min.c的模塊,並且通知了hello.c去調用一下並顯示出最小的數據出來。於是編譯相應的就改成了

gcc max.c min.c hello.c -o hello.out

沒錯,就是將相關的.c文件列舉上去就可以,很容易很簡單,可是如果項目一旦復雜,.c文件有上千個,那豈不要累死程序員,累死那個發布的同事了嗎?當然不可以,我們對於每個人都是不拋棄不放棄。所以我們使用Makefile來解救他們。 

#this is a make file for hello.out
hello.out:max.c min.c hello.c 
      gcc max.c min.c hello.c -o hello.out

那么接下在bash里面直接輸入make就可以了。當然,作為第一次使用,我還是沒有忘記使用make -v看一下我使用的版本號是多少:

http://images.cnblogs.com/cnblogs_com/SLKnate/628534/o_makeVersion.png

最后執行的結果也是想要的預期結果。

 

4, 似乎很完美了,可是我們去看看Makefile的內容,總有一種異樣的怪怪感。當然如果沒有發現也很正常,畢竟我們還只有三個文件,而且現在的機器也是很快的,執行make時也不會有啥差異的。其實如果我們去看網上下載的Makefile 之后,發現很多不怎么變的文件,都會有.o的形式存在的。另外源代碼里面可能還充斥着很多.h的文件。那么這些文件是干什么的。為什么會存在這類文件呢?在回答這類問題之前,首先我要申明,不是非要以.o, .h來命名,只不過約定俗成罷了,.o就是模塊文件,也就是不常變動的.c 文件可以先編譯成.o作為模塊保存下來。 .h文件是給調用者說明的,他一般只包含.c文件的方法的簽名即可。說得更接近高級語言一點,就是相當於c#(java)里的interface.

接下來,我就把max.c轉成max.o, 將min.c轉成min.o保存下來。並且生成兩份.h文件出來,最后也提供一份更接近生產的Makefile,注意這個M是要大寫的,這也是約定,而且這個約定是不能變的。

gcc -c max.c 
gcc -c min.c

 然后max.h和min.h文件輸入的內容是:

int max(int a, int b);

 和

int min(int a ,int b);

最后的Makefile

#this is a make file for hello.out
hello.out:max.o min.o hello.c 
      gcc max.o min.o hello.c -o hello.out
max.o:max.c
      gcc -c max.c
min.o:min.c
      gcc -c min.c

 

5,  最后,我把我的代碼全部貼上來吧。

int max(int a, int b)
{
    if(a>b) return a;
    return b;
}
max.c
int max(int a, int b)
{
    if(a<b) return a;
    return b;
}
min.c
#include <stdio.h>
#include "max.h"
#include "min.h"

int main(int argc, char* argv[])
{
    int a=33;
    int b=22;
    int maxNo=max(a,b);
    int minNo=min(a,b);
    printf("the max number is %d"\nthe min number is %d\n",maxNo,minNo);  
    return 0;   
}
hello.c

 

6,  關於我的第一個linux的C程序就是這樣子的,Happy ending, right?

 

7,  不,這樣的結局並不完美。作為一個程序員,我並沒有覺得很happy,因為上面並沒有講到如何調試。都是一次過的簡單程序,能夠一次性將所有程序邏輯(包括復雜的)寫出來就真是大牛逼人物了。 靜態的編譯錯誤還好說,make階段就能發現,可是有些邏輯卻不是那么容易發現的。程序員的終極武器debug就要祭出了。在linux里面一般用的就是gdb工具。按照慣例看一下我的版本先:

 http://images.cnblogs.com/cnblogs_com/SLKnate/628534/o_gdbVersion.png

  為了調試我上面的那個小程序,我將所有的*.o文件和hello.out先刪除掉。

rm -rf *.o
rm -rf hello.out

然后修改Makefile成如下:

#this is a make file for hello.out
hello.out:max.o min.o hello.c 
      gcc -g max.o min.o hello.c -o hello.out
max.o:max.c
      gcc -g -c max.c
min.o:min.c
      gcc -g -c min.c

 執行make之后。繼續輸入

gdb ./hello.out

 這樣就加載了我們hello.out進了內存,而且可以調試了。至於什么是棧內存、堆內存、數據內存,代碼內存這些,我就不說了,可以回去翻翻大學教程或者網絡上自己搜索一下吧,貼出我的一些簡單的調試操作吧:

 http://images.cnblogs.com/cnblogs_com/SLKnate/628534/o_gdbNormalProcess.png

 

8, 最后解決一個小問題,就是在上面的圖中,我們可以看到其中出現了一個錯誤說Missing separate debuginfos, use: debuginfo-install glibc-2.17-78.el7.x86_64

其實要解決這個問題,也很簡單,直接在bash下面輸入

debuginfo-install glibc

前提是我已有/etc/yum.repos.d/CentOS-Debug.repo如下:

# CentOS-Debug.repo
#
# The mirror system uses the connecting IP address of the client and the
# update status of each mirror to pick mirrors that are updated to and
# geographically close to the client.  You should use this for CentOS updates
# unless you are manually picking other mirrors.
#

# All debug packages from all the various CentOS-7 releases
# are merged into a single repo, split by BaseArch
#
# Note: packages in the debuginfo repo are currently not signed
#

[base-debuginfo]
name=CentOS-7 - Debuginfo
baseurl=http://debuginfo.centos.org/7/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-Debug-7
enabled=0
#
CentOS-Debug.repo

如果沒有就需要先到http://debuginfo.centos.org/7/x86_64/ 找到與內核完全一樣的debuginfo. 例如機器的內核是CentOS Linux 7 (Core) Kenerl 3.10.0-229.el7.x86_64 on an x86_64,  就是在輸入用戶名的登錄時可以看到這個信息。 那么就應該

wget http://debuginfo.centos.org/7/x86_64/kernel-debuginfo-3.10.0-229.el7.x86_64.rpm
wget http://debuginfo.centos.org/7/x86_64/kernel-debuginfo-common-x86_64-3.10.0-229.el7.x86_64.rpm

 然后rpm安裝下載到的rpm包,不過我認為可能不需要下載這兩個應該也是可行的。最后仿照配置yum源並執行

debuginfo-install glibc

就可以解決這個問題。

 

9, 至於如何使用gdb,網上找到兩篇介紹文章

http://www.cnblogs.com/hankers/archive/2012/12/07/2806836.html

http://blog.csdn.net/feixiaoxing/article/details/7199643

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM