makefile條件編譯
① c語言條件編譯用常量表達書做條件,此常量表達式必須在編譯時可求也就能不能讓條件由scanf得到的
程序在編譯時是不會執行scanf的 所以不能
② makefile中:all和:debug是什麼意思
一般,在開發測試階段用debug版本,而上線發布用release版本。 使用Makefile定製編譯不同版本,避免修改程序和Makefile文件,將會十分方便。 讀了一些資料,找到一個解決方法,Makefile預定義宏與條件判斷,結合make預定義變數,進行條件編譯。 ...
③ C語言學習路線
一,UNIX下C語言的學習路線。
工具篇
「公欲善其事,必先利其器」。編程是一門實踐性很強的工作,在以後的學習或工作中,將常常會與以下工具打交道, 下面列出學習C語言編程常常用到的軟體和工具。
(一)操作系統
在UNIX或linux系統中學習C很方便,所以在開始的學習旅程前請先選擇一個UNIX或Linux操作系統。
目前可供個人免費使用的UNIX或Linux系統有FreeBSD、RedHat Linux、SUSE Linux等,而且在安裝包中還提供很多實用的工具,如:gcc, make等。
如果您一直使用Windows,身邊又沒有多餘的機器安裝UNIX,則可以使用VMware,通過VMware安裝虛擬系統。
(二)編譯工具
目前絕大多數Unix或Lnux系統都提供CC或GCC編譯器,最簡單的cc命令格式如下:
cc -o hello hello.c
在unix shell環境中敲入上面的代碼會將hello.c程序編譯成可執行文件hello。
make 工具如 GNU make、System V make 和 Berkeley make 是用來組織應用程序編譯過程的基本工具,但是每個 make 工具之間又有所不同。
大部分UNIX和Linux程序都是通過運行make來編譯的。make工具會讀取一個包含指令的文件(這個文件的名字通常都是 makefile 或 Makefile,不過後文中統一稱之為 「makefile」),並執行各種操作來編譯程序。
(三)調試工具
最簡單的調試工具:為程序添加列印語句
在對程序的運行機制有了一定的了解後,可以實用一些工具幫助進行調試,當然得學習一下這些工具得使用,如:dbx,gdb等。
還有一些內存工具可以幫查找內存泄漏或緩沖區溢出等一些問題,如:memwatch,yamd等
(四) 其他工具
1. vi或vim
Unix下文本編輯器。主要靠一堆命令來編輯文本文件,學Unix編程最好熟悉並熟練使用vi編輯器。
當然在實際工作中,可能需要一個集成編碼環境或一個功能強大的圖形化編輯工具。
2.netterm
最著名的網路終端軟體之一,可以使用它方便的連接到主機系統中。
3.Secure shell
一個支持ssh協議得客戶端工具,多數情況下用來連接linux系統。
書籍篇
「書是人類進步得階梯」。學習一門新的知識,當然要選擇幾本適合自己得書籍,下面介紹一些我自己學習C語言使用過的書籍:
1.《C primer plus》
推薦理由:適合作為入門書和基本函數查詢得參考資料。本書最新版為第五版,以ANSI C99為標准詳細介紹了C語言。
2.《The C programming_Language》
推薦理由:C語言之父得作品權威性毋庸置疑。雖然書籍出版時間比較老,好像也沒更新,不過仍不失為經典書籍,網上有這本書得英文電子版提供下載。
3.《C 專家編程》
推薦理由:本書可以幫助有一定經驗的C程序員成為C編程方面的專家,最關鍵的是本書寓教於樂,充分享受編程的樂趣。
4.《C缺陷與陷阱》
推薦理由:書中所揭示的知識能幫助繞過C語言自身得陷阱和缺陷,減少代碼中許多常見的Bug。
5.《unix環境高級編程》
推薦理由:既然是UNIX環境下C編程,就不得不說說UNIX編程書籍。Stevens先生的《unix環境高級編程》是竭力推薦的,也是案頭必備(如果對網路編程有興趣的,可以學習一下Stevens先生的《UNIX網路編程》兩卷,如果覺得還不過癮,可以再看看《TCP/IP詳解》三卷)。
6.《計算機編程藝術》
推薦理由:演算法大師得嘔心瀝血之作。計劃出版五卷書,目前好像已出版3卷。對演算法有興趣得可以研究一下。
過程篇
1.學習C語法
語法的學習對於一個具有編程底子的來說,就很輕鬆了;即使以前沒有學習過其他編程語言,我相信有2個星期,也能輕松搞定。
需要注意的是,不要太糾纏於語言的細節,比如:運算符優先順序與結合性的問題等。
2.學習C標准庫
ANSI C庫把函數分為不同的組,每個組都具有與之相關的頭文件。C語言標准庫相對於其他語言,比如C++,Java來說是非常短小精悍的,但首先應著重對以下庫進行學習:
ctype.h:字元處理
math.h:數學庫
stdio.h:標准I/O庫
stdlib.h:通用工具庫
string.h:字元串處理
time.h:時間和日期
如果想了解完成的ANSI C庫,可以購買相關的書籍,這些書籍一般會詳細介紹每個函數的用戶和一些注意點;
3.攻克C的難點
C語言聲明:
C語言的聲明確實覺得恐怖,比較晦澀難懂,而且聲明的形式和使用的形式還類似。比如如下的聲明恐怕就連很多熟悉C多年的程序員也不是一眼就能看出來的:
char * const * (*next)();
那麼有沒有一種好的記憶方法或規則來搞清楚呢,好像沒有,如果有的話也不是這樣折磨人了。不過可以看看《C專家編程》第三章的內容,或許會有所收獲。
也只能多學多練了,所謂熟能生巧嘛,希望這個問題不要在你的心靈上留下陰影。
數組與指針:
數組與指針的關系,在標准中並沒有作很詳細的規定,而且好多C入門的書籍在這個問題上並沒有給出很詳細的說明,所以會給人造成很多誤解。
對於這個問題,可以參考《C缺陷與陷阱》4.5節和《C專家編程》第4,9,10章,相信這裡面的內容搞透徹,以後就不會再被這個問題搞迷惑。
指針與內存:
如果以後編寫規模較大的程序,可能發現這個問題可能會是最大的煩惱,而且可能會是消耗最多調試時間的事項。
C版本的問題:
得特別小心該問題,最好不要的程序中混合使用不同版本C的特性,否則會帶來很迷惑的問題。如果一定要用,最好清楚自己在做什麼。
4. UNIX環境編程
學習了以上內容之後,就可以進行unix環境編程了。不過可能需要對操作系統理論有一點點的了解,這樣學起來會比較輕松一些。
Unix環境編程,應該著重IO和進程兩大塊內容。《Unix環境高級編程》中對Unix環境編程有著非常詳細且深入的論述,而且書中有大量實用性例子程序,不過可能得花上幾個月得時間,好好啃一啃了。
在扎實掌握以上內容,不代表得C語言學習支路已經完成,相反,才剛剛開始。以後需要用學到得知識去解決大量不同實際問題,在不斷得實踐過程中,會近一步加深對C的理解。有了以上基礎之後,會發現,在實踐過程中需要的其他知識,會非常快速的掌握。
二,Windows程序員的學習路線
1.當然要熟悉下C語言了 入門可以選用潭浩強的 《C程序設計》(當然最好能讀C Programming Language)特別要對其中的指針,結構體等東西一定要搞清楚了(要學好的很好至少要花費一個月時間) 為什麼要從C開始呢:<1> C好學 <2> 大多數的操作系統核心部分是用C開發的 <3> C的效率高且語言成熟
2.在1的基礎之上一定要認真學習一下數據結構 對C++程序員來說良好的數據結構可以讓一個程序員很輕松的完成程序設計 糟糕的數據結構可以把一個程序員累死 推薦書籍:嚴蔚敏的《數據結構(C語言版)》或北京大學的一本中C++版的數據結構 書中說到的每個主體在程序設計中都會用到 認真學好會對的以後的C++程序設計有太多的好處 (3個月時間)
3.學好了2之後可以學習下《C++ PROGRAM DESIGN》這本書初步介紹了C++和如何使用C++寫出Windows下的程序(要學好至少要花費3個月時間)
4.在3的基礎之上可以讀一本叫《Windows 95 程序設計》(它的最新版本是Programming Windows)這是一相Windows程序設計的領域的不朽之作(3個月時間) 通過2和3的學習已經成為了一個可以設計Windows程序的程序員了 要想更好的設計Windows程序設計 一定要藉助框架結構不可 為什麼:框架結構可以加快我們程序設計的速度 雖然使用框架使得我們的程序的效率低了那麼一點 但隨著當今計算機的運算能力的提升,不會感覺到這一點點的性能損失的反而會因為你使用的框架結構而使你的程序設計加快了速度 使用框架結構才算一個真正的VC++程序員
5.在4的基礎之上可以看一些簡單的MFC程序設計的書比如《Visual C++入門教程》之類的圖書 這可以使你能寫出一些帶有通用控制項的MFC程序 (1個月時間)
6.在5的基礎之上已經可以很快開發一個軟體了 但不了解MFC框架運行機制是很不好的 了解MFC的運行機制可以使以後的MFC程序設計工作做的更好 推薦書籍侯傑的《深入淺出MFC》 但這本書真的不適合初學者當你有了一定的開發經驗以後這本書對來說確實很好 若很熟悉Windows下的SDK程序設計並打算或已經開始使用MFC進行軟體開發 那這本書對來說再好不過了 (2個月時間)
7.在6的基礎之上可以看下這本書《VC++技術內幕》由潘愛民譯的 推薦看原著(3個月)
8.在以上基礎之上為了更好的使用VC++這個工具 推薦看一下《VC++6.0寶典》(3個月) 從開發工具的角度講這本書寫的很好
9.為了更好的工作可以參考一下VC++程序設計百例
10.之後可以看一下《Windows核心編程》 這本書很好的講解了Windows的編程 對你寫系統程序很有好處的 推薦看原版
11.只了解其形不算真正的了解 之後還要認真的讀一下Windows的內核源碼 相信WRK 很容易找到的 可以配合《深入解析Windows操作系統》《Windows內核原理與實現》和《Windows內核情景分析》
12.其它一些東東《COM原理》(潘愛民) OpenGL D3D VC的資料庫編程 圖形圖像 音視頻處理和網路都要有所了解和會使用
13.要做到一個好的程序員一定要對驅動程序有所了解所以寫一個文件驅動之類的東東是很有必要的
14.經過以上各步的學習完全成為一個優秀的Windows程序員了(前提是每一步要學好)
15.漏了一些重要的東東 編譯原理 匯編及 組成原理 和設計模式等也是很重要的東東 只有學好了這些才能明白語言為什麼要這樣組織才能高效。
④ c代碼編程問題,怎樣初始化已定義的結構體
第一章:前言
對於c語言,有人認為它已經落伍了.對於這個問題,仁者見仕,智者見智.的確,c++比c有更強大的諸多優勢.但c++是建立在c之上的.這也是herbert schildt所著的<>在全世界暢銷不衰的原因.更何況,要深入學習linux就必需要有相當的c功底.(這也是我搜集整理本文的根由:-)
現結合個人在編程中的體會,為使新手少走彎路,為老手錦上添花,因此無論你是使用c或c++編程,也無論你是程序設計的初學者還是成熟的專業人員,均會發現,本文將會對你有所收益.當然,我盡力寫得清晰易懂,又不古板.
我愛c.(正如世人愛上帝一樣:-)..
你可以在forum.linuxaid.com.cn上獲得此帖的文本.而其html版本正在趕制之中......
第二章:約定
專業的源程書寫風格.
先看看世界級c大師的源程書寫風格.如 steve maguire 就有許多不錯的建議.
[]倡導使用易於理解的"匈牙利式"的命名約定.
所有的字元變數均以ch開始; 如: char ch_****;
所有的位元組變數均冠以b; 如: byte b_****;
所有的長字變數均冠以l; 如: long l_****;
所有的指針變數均冠以p; 如: char *p_ch_****;
建議類型派生出的基本名字之後加上一個以大寫字母開頭的"標簽".如:
分析 char **ppchmydata;
其讓人一眼就能看出它****一個指向字元指針mydata的指針.
"匈牙利式"命名的最大不足是難念:-(( .但相對於不是總統演講稿的c源程來說,這又算得了什麼?想想看以下的數據命名:
char a,b,c;
long d,e,f;
[]倡導規范書寫.
如果你思如泉湧,而不去也不及顧慮書寫格式,那也沒關系.在將其交出去之前,用cb命令格式化你的源程.雖然源程的格式不會影響到你編譯結果的正確性,但切記,能讓其他的程序員能輕松地閱讀它.否則沒人會理你的.
關於cb命令的更多用法,可以用man cb來參考其手冊頁.
當然除了cb之外,還有更多更好的.但cb是你在任何unix(linux)上都找得到的.更何況它並不差
第三章:開始任務
開始任務之前,先做個深呼吸!
[]其他文檔你准備好了嗎?
你是不是除了c源程之外一無所有了嗎?兵馬未動,糧草先行.你必須先清楚該程序所要完成的功能.在開始寫程序之前,對程序的功能應有規范說明.書寫規范書和確知程序功能的一個方法是先編寫相應的操作手冊.如果你是一人單干,勸你首先寫需求書.切記切記,這對你意味著事半功倍的大好事.
一個實例:我計劃為本行的信貸子功能模塊打一個補丁.我用10周的時間用來寫規劃書,需求書,操作流程,使用說明等等文檔.之後用2周的時間編寫程序,在初步測試(1周)後遞交給各信貸部門測試使用.然後根據反饋的信息再更改相應文檔,並根據文檔修改源程.6個月後發布正式版.
[]一定該遵循ansi標准嗎?
如果你僅使用ansi的標准首標文件,恭喜你,你的程序有著全世界范圍內的廣泛支持和兼容.光明無限.但你必須在通用與專用之間做出取捨,對不起,我幫不了你.
我的原則是:核心用ansi,界面按需而取.這樣在轉換平台時僅需另編用戶界面而已.實用至上嘛.
附:ansi 標准c頭文件
是不是很寒酸?
[]再續前緣?
在得到新任務之後並在開始該新任務之前應馬上回想有哪些是曾經擁有的.舊調重彈遠比另起爐灶來的高效與環保.
[]是否該有自已的庫?
我的答案是應該有自已的特色庫,並與ansi兼容.與3.8不同的是,你僅需在源程序之後附上自已的專用庫就可以了.其次在有了自已的庫後,源碼會很精煉的.不用去羨慕別人了吧.
[]要學會條件編譯.注意你的平台特性.(高手的標志?)
除非你確定你要寫的程序是在某特定的os特定的硬體平台而量身定做.否則應注意數據類型的長度,精度都是不同的,不要想當然.有時甚至是不同的編譯器的差異都要考慮考慮.
....
....(歡迎您來充實此處空白)
....
好了,在任務中,又有哪些細節呢?
[]我是不是葛郎台?
不要那麼吝嗇.在源程序中加入詳盡的注釋以使自己和他人即使在許多年以後仍能讀明白它是什麼樣的程序.
用注釋行分離各個函數.
[]刪除不需要的代碼時要小心.
一個好建議是:使用#ifdef del,而不是簡單地注釋掉甚至是粗暴地直接dd.如果你是使用/* ... */,但一旦要刪除的代碼有很多行,或注釋中以有注釋時,這就可能不那麼好使了.
[]如何給源程序文件命名?
表現特色且不與任何原有應用名相同.一個簡單地方法就是試試看,系統有什麼樣地反應?
[]一次只修改一個地方.
[]一次只編寫一個單一功能的函數。
[]編寫通用程序.
只有當程序編寫完,並且完成了所需要的性能要求之後,再反過頭來優化該程序.
[]不要使用a.out作為結果.你大可以使用與源程相同的可執行文件名.
[]是否一定要用vi編輯?
linux下有許多專用編程編輯器.它們能使你有更高的效率和更低的低級輸入錯誤,但我還是要勸你至少要熟練掌握vi.畢竟vi遍地開花.
[]協同作業.請相信,你不是在孤軍作戰.因此,你有必要熟練掌握一些其它的工具
第四章:使用lint
lint沒有你想像中的那樣糟糕.相反,一旦源程序形成了沒有lint錯誤的形式,將很容易保持下去,並享受到如此而帶來的好處.
[]在cc(gcc)之前就應使用lint.
lint是一語法檢查程序,對於這個多嘴的婆婆來說,你應有足夠的耐心.雖然你知道自已在干什麼,但在cc之前使用lint總是一個好習慣.
[]lint有哪些特色?
在編譯之前使用lint的重要原因是lint不但能發現ansi c中的語法錯誤,而且也能指出潛在的問題或是難於移植於另一機器的代碼問題.除了能指出簡單語法錯誤之外,linut還能基於以下原因指出另外的錯誤:
a.無法達到的語句.
b.沒有進入循環.
c.沒有被使用的變數.
d.函數參數從未使用.
e.沒有賦值之前自動使用參數.
f.函數在有些地方有返回值,但在其他地方不返回.
g.函數調用在不同地方使得參數個數不同.
h.錯誤使用結構指針.
i.模糊使用操作符優先順序.
呵呵呵,挺有用的吧!
[]如何控制lint的輸出?
有時lint會有一大屏一大屏的警告信息.但似乎並未指出錯誤.為了找出潛在的錯誤則需費心費力地瀏覽這些大量的警告信息.
但如果你的程序會分出幾個獨立的模塊,在初級啟動lint時不要用可選項.當對這些模塊進行更改或擴充時,可以忽略與代碼無關的某些警告.為此可用以下選擇項:
-h 對判別是否有錯,類型是否正確不給出啟發式測試.
-v 不管函數中沒有定義的參數
-u 不管被使用的變數和函數沒有定義或定義了但沒有使用.
[]乾脆,在程序中插入指令來影響lint運行.它看樣子有些像注釋.
/*notreached*/ 不可達到的代碼不給信息說明.
/*varargsn*/ 函數的變數個數不作通常的檢查,只檢查開始n個參數的數據類型.
/*nostruct*/ 對下一個表達式不作嚴格類型檢查.
/*argused*/ 下一函數中,不給出沒被使用參數的警告信息.
/*lintlibrary*/ 置於文件的開頭,它將不給出沒被使用函數的警告信息.
關於lint的更多用法,請用man lint來獲知
第五章:使用make
[]什麼是make?
unix(linux)是一個天生的開發平台,我為此感到高興.make是一個強力的工具.它能依賴的源代碼塊並組成一程序,使得很容易建立一可執行程序.make就是這種有依賴關系的部分和代碼之間所作的規格說明.
[] 所有的程序都要使用make?
是的.盡管你只有幾個簡單的模塊,但你需要有一種結構來支持它從簡單走向復雜.除非你的程序已經蓋棺定論.
[]makefile由哪些組成?
makefile由以下幾個部分組成:
注釋.
^^^^
使用#符號插入.make將忽略#之後的任何內容以及其後的return鍵.
變數.
^^^^
make允許定義與shell變數類似的有名變數.比如,你定義了sources=prog.c,那麼該變數的值$(scoures)就包含了源文件名.
依賴關系.
^^^^^^^^
左邊是目標模塊,後接一冒號.再接與該模塊有依賴關系的模塊.
命令.
^^^^
以tab鍵開始(即使用相同數量的空格也不能代替它).
[]makefile示例
下面介紹一個簡單的示例來說明make的用法.假設你的程序有兩個源文件main.c和myc.c,一個位於子目錄include下的頭文件myhead.h,一個庫由****源文件myrout1.c,myrout2.c,myrout3.c產生.
其makefile文件為:
#一個基本的makefile文件.
#其中包括個人的頭文件和個人庫.
headers=include/myhead.h
sources=main.c myc.c
proct=$(home)/bin/tool
lib=myrout.a
libsoures=myrout1.c myrout2.c myrout3.c
cc=cc
cflags=-g
all:$(proct)
$(proct):$(sources)
$(cc)$(cflags) -o $(proct)$(sources)
lint:$(proct)
lint $(sources)$(libsources)
哈哈,挺象shell編程的.如果你與我一樣使用linux下的gcc,那麼只要把上面的cc=cc改為cc=gcc即可.怎麼樣,想來一個更復雜點的嗎?
[]一個更為復雜的makefile
你是否注意到,在上例中,只要啟動make,就會重新編譯所有源代碼.
如果你能看懂以下的makefile,恭喜恭喜,你通關了.
#一個更為復雜的makefile
headers=include/myhead.h
soures=main.c myc.c
objects=main.c myc.c
proct=$(home)/bin/tool
lib=myrout.a
libsources=myrout1.c myrout2.c myrout3.c
libobjects=$(lib)(myrout1.o)$(lib)(myrout2.o)$(lib)(myrout3.o)
include=include
cc=cc
cflags=-g -xc
lint=lint
lintflags=-xc
all:$(proct)
$(proct):$(objects)$(lib)
$(cc)(cflags)-o$(proct)$(objects)$(lib)
.c.o: $(headers)
$(cc)$(cflags) -c i$(include)$<
$(lib):$(headers)$(libsources)
$(cc) $(cflags) -c $(?:.o=.c)
ar rv $(lib) $?
rm $?
.c.c:;
lint: $(proct)
$(lint)$(liniflags)$(sources)$libsources)
第六章:優質無錯編程
親愛的,檢查一下,你是否注意到了以下的細節?也就是說,你是否是一個合格的,能編寫優質無錯代碼的程序員?要永遠記住,編寫無錯代碼是程序員的責任,而不是測試員.(摘錄於本人的"細節頁",因此本節將永遠不會保持完整,歡迎您來充實她)
[]所有程序員至少出現過的一個錯誤:
if(a=3){......}如果a等於3,那麼......
你至少要養成這樣的習慣:當判斷一個變數與一個常量是否相等時,將常量寫在前面.這樣即使你一不小心寫成這樣:if(3=a){......}在cc 之前就可以很容易發現它.
[]老調重彈:邏輯操作符的優先權.
我不願多嘴.總之,如果你一定要編寫如下代碼時:
if(a&0x1&&b&0x2){......}
你的手頭最好有一本詳盡的指南.或者你是這方面的專家.
[]盡量不使用int數據類型.
這僅是一個忠告.你大可使用char,short,long數據類型.若干年以後,當你成長為高手之時,你會發現此時我的良苦用心.
[]對於非整型函數一定要完整定義.
如 long float jisuan(char charr[],int chnum)
{ long float lmydata;
...
...
return(lmydata); }
[]對於非整型函數的輸入要當心.
如 long float lfnum;
...
...
scanf("%lf",&lfnum);
[]float 型的有效數字為7位.當多於7位時,第8位及以後的位將不準確,可以將其定義為long float型.
[]文件的輸入出盡量採用fread fwrite函數.只有當另有用途時才用fprintf fscanf 函數
⑤ vcs生成覆蓋率時,條件編譯的頂層會被當做不同的項目,合並覆蓋率時會出錯,怎麼解決
要生成覆蓋率報告,要在編譯和模擬的時候,加入一個選項。 -cm line | fsm | tgl | cond , 指定生成針對什麼條件的覆蓋率報告。如下的makefile,就生成上述四個的覆蓋率報告。注意,編譯和模擬,都要加上-cm這個選項。執行 make vcs , make sim後,會生成simv.vdb文件夾,該文件夾下包含了覆蓋率的內容,但是我們需要將內容生成報告,這樣,才方便我們查看。生成報告,使用的是 urg命令,該命令也是屬於vcs工具裡面的-dir: 指定 .vdb文件夾的位置report: 指定生成報告的格式,報告格式有兩種,一種網頁格式,一種text格式。這里,both代表生成兩種。執行 make urg後,就會生成both文件夾。 這文件夾下的文件,就是覆蓋率報告了。打開dashboard.html。可以看到整體的一些信息。但是我們關心的是設計的,而不是testbench的。點擊hierarchy,得到層次。點擊u1,也就是設計的頂層。可以看到關於該頂層的信息。因為在頂層,都是調用各個子模塊(這里是調用 band_generaterx_tx, uart_txd模塊),所以沒有line的覆蓋率統計,但是有TOGGLE的覆蓋率統計,也就是信號的翻轉。從上面可以看出,對於rst_n信號,沒有從1->0的翻轉,而這個信號是testbench中傳遞的,因此看出,在testbench設計,對於rst_n信號產生,有bug。點擊左下角的uart_txd_1,查看該模塊的信息。 對於該設計,因為有具體的實現,所以可以看到有line的覆蓋率,toggle的覆蓋率,FSM的覆蓋率。對於line覆蓋率,從報告看出,總共有42行,覆蓋到了41行。通過查看代碼,可以知道是哪一行沒有被執行到。對於toggle覆蓋率。從報告看出,只有rst_n有問題,而這問題是testbench的的bug造成的。對於FSM的檢查。從報告看出,每個狀態都有被覆蓋到。但是從有些狀態跳轉到另外的狀態,沒有被覆蓋到。因此造成FSM的覆蓋率不高。通過查看覆蓋率報告,可以查找到設計的缺陷,從而進行修正。
⑥ 如何編譯linux版本
編譯安裝內核
下載並解壓內核
內核下載官網:https://www.kernel.org/
解壓內核:tar xf linux-2.6.XX.tar.xz
定製內核:make menuconfig
參見makefile menuconfig過程講解
編譯內核和模塊:make
生成內核模塊和vmlinuz,initrd.img,Symtem.map文件
安裝內核和模塊:sudo make moles_install install
復制模塊文件到/lib/moles目錄下、復制config,vmlinuz,initrd.img,Symtem.map文件到/boot目錄、更新grub
其他命令:
make mrprobe:命令的作用是在每次配置並重新編譯內核前需要先執行「make mrproper」命令清理源代碼樹,包括過去曾經配置的內核配置文件「.config」都將被清除。即進行新的編譯工作時將原來老的配置文件給刪除到,以免影響新的內核編譯。
make dep:生成內核功能間的依賴關系,為編譯內核做好准備。
幾個重要的Linux內核文件介紹
config
使用make menuconfig 生成的內核配置文件,決定將內核的各個功能系統編譯進內核還是編譯為模塊還是不編譯。
vmlinuz 和 vmlinux
vmlinuz是可引導的、壓縮的內核,「vm」代表「Virtual Memory」。Linux 支持虛擬內存,不像老的操作系統比如DOS有640KB內存的限制,Linux能夠使用硬碟空間作為虛擬內存,因此得名「vm」。vmlinuz是可執行的Linux內核,vmlinuz的建立有兩種方式:一是編譯內核時通過「make zImage」創建,zImage適用於小內核的情況,它的存在是為了向後的兼容性;二是內核編譯時通過命令make bzImage創建,bzImage是壓縮的內核映像,需要注意,bzImage不是用bzip2壓縮的,bzImage中的bz容易引起誤解,bz表示「big zImage」,bzImage中的b是「big」意思。 zImage(vmlinuz)和bzImage(vmlinuz)都是用gzip壓縮的。它們不僅是一個壓縮文件,而且在這兩個文件的開頭部分內嵌有gzip解壓縮代碼,所以你不能用gunzip 或 gzip –dc解包vmlinuz。 內核文件中包含一個微型的gzip用於解壓縮內核並引導它。兩者的不同之處在於,老的zImage解壓縮內核到低端內存(第一個640K),bzImage解壓縮內核到高端內存(1M以上)。如果內核比較小,那麼可以採用zImage 或bzImage之一,兩種方式引導的系統運行時是相同的。大的內核採用bzImage,不能採用zImage。 vmlinux是未壓縮的內核,vmlinuz是vmlinux的壓縮文件。
initrd.img
initrd是「initial ramdisk」的簡寫。initrd一般被用來臨時的引導硬體到實際內核vmlinuz能夠接管並繼續引導的狀態。比如initrd- 2.4.7-10.img主要是用於載入ext3等文件系統及scsi設備的驅動。如果你使用的是scsi硬碟,而內核vmlinuz中並沒有這個 scsi硬體的驅動,那麼在裝入scsi模塊之前,內核不能載入根文件系統,但scsi模塊存儲在根文件系統的/lib/moles下。為了解決這個問題,可以引導一個能夠讀實際內核的initrd內核並用initrd修正scsi引導問題,initrd-2.4.7-10.img是用gzip壓縮的文件。initrd映象文件是使用mkinitrd創建的,mkinitrd實用程序能夠創建initrd映象文件,這個命令是RedHat專有的,其它Linux發行版或許有相應的命令。這是個很方便的實用程序。具體情況請看幫助:man mkinitrd
System.map是一個特定內核的內核符號表,由「nm vmlinux」產生並且不相關的符號被濾出。
下面幾行來自/usr/src/linux-2.4/Makefile:
nm vmlinux | grep -v '(compiled)|(.o$$)|( [aUw] )|(..ng$$)|(LASH[RL]DI)' | sort > System.map
在進行程序設計時,會命名一些變數名或函數名之類的符號。Linux內核是一個很復雜的代碼塊,有許許多多的全局符號, Linux內核不使用符號名,而是通過變數或函數的地址來識別變數或函數名,比如不是使用size_t BytesRead這樣的符號,而是像c0343f20這樣引用這個變數。 對於使用計算機的人來說,更喜歡使用那些像size_t BytesRead這樣的名字,而不喜歡像c0343f20這樣的名字。內核主要是用c寫的,所以編譯器/連接器允許我們編碼時使用符號名,而內核運行時使用地址。 然而,在有的情況下,我們需要知道符號的地址,或者需要知道地址對應的符號,這由符號表來完成,符號表是所有符號連同它們的地址的列表。
Linux 符號表使用到2個文件: /proc/ksyms 、System.map 。/proc/ksyms是一個「proc file」,在內核引導時創建。實際上,它並不真正的是一個文件,它只不過是內核數據的表示,卻給人們是一個磁碟文件的假象,這從它的文件大小是0可以看 出來。然而,System.map是存在於你的文件系統上的實際文件。當你編譯一個新內核時,各個符號名的地址要發生變化,你的老的System.map 具有的是錯誤的符號信息,每次內核編譯時產生一個新的System.map,你應當用新的System.map來取代老的System.map。
雖然內核本身並不真正使用System.map,但其它程序比如klogd, lsof和ps等軟體需要一個正確的System.map。如果你使用錯誤的或沒有System.map,klogd的輸出將是不可靠的,這對於排除程序故障會帶來困難。沒有System.map,你可能會面臨一些令人煩惱的提示信息。 另外少數驅動需要System.map來解析符號,沒有為你當前運行的特定內核創建的System.map它們就不能正常工作。 Linux的內核日誌守護進程klogd為了執行名稱-地址解析,klogd需要使用System.map。System.map應當放在使用它的軟體能夠找到它的地方。執行:man klogd可知,如果沒有將System.map作為一個變數的位置給klogd,那麼它將按照下面的順序,在三個地方查找System.map: /boot/System.map 、/System.map 、/usr/src/linux/System.map
System.map也有版本信息,klogd能夠智能地查找正確的映象(map)文件。
makefile menuconfig過程講解
當我們在執行make menuconfig這個命令時,系統到底幫我們做了哪些工作呢?這裡面一共涉及到了一下幾個文件我們來一一探討
Linux內核根目錄下的scripts文件夾
arch/$ARCH/Kconfig文件、各層目錄下的Kconfig文件
Linux內核根目錄下的makefile文件、各層目錄下的makefile文件
Linux內核根目錄下的的.config文件、arch/$ARCH/configs/下的文件
Linux內核根目錄下的 include/generated/autoconf.h文件
1)scripts文件夾存放的是跟make menuconfig配置界面的圖形繪制相關的文件,我們作為使用者無需關心這個文件夾的內容
2)當我們執行make menuconfig命令出現上述藍色配置界面以前,系統幫我們做了以下工作:
首先系統會讀取arch/$ARCH/目錄下的Kconfig文件生成整個配置界面選項(Kconfig是整個linux配置機制的核心),那麼ARCH環境變數的值等於多少呢?它是由linux內核根目錄下的makefile文件決定的,在makefile下有此環境變數的定義:
SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
-e s/arm.*/arm/ -e s/sa110/arm/ \
-e s/s390x/s390/ -e s/parisc64/parisc/ \
-e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
-e s/sh[234].*/sh/ )
..........
export KBUILD_BUILDHOST := $(SUBARCH)
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?=
或者通過 make ARCH=arm menuconfig命令來生成配置界面
比如教務處進行考試,考試科數可能有外語、語文、數學等科,這里我們選擇了arm科可進行考試,系統就會讀取arm/arm/kconfig文件生成配置選項(選擇了arm科的卷子),系統還提供了x86科、milps科等10幾門功課的考試題
3)假設教務處比較「仁慈」,為了怕某些同學做錯試題,還給我們准備了一份參考答案(默認配置選項),存放在arch/$ARCH/configs/目錄下,對於arm科來說就是arch/arm/configs文件夾:
此文件夾中有許多選項,系統會讀取哪個呢?內核默認會讀取linux內核根目錄下.config文件作為內核的默認選項(試題的參考答案),我們一般會根據開發板的類型從中選取一個與我們開發板最接近的系列到Linux內核根目錄下(選擇一個最接近的參考答案)
4).config
假設教務處留了一個心眼,他提供的參考答案並不完全正確(.config文件與我們的板子並不是完全匹配),這時我們可以選擇直接修改.config文件然後執行make menuconfig命令讀取新的選項。但是一般我們不採取這個方案,我們選擇在配置界面中通過空格、esc、回車選擇某些選項選中或者不選中,最後保存退出的時候,Linux內核會把新的選項(正確的參考答案)更新到.config中,此時我們可以把.config重命名為其它文件保存起來(當你執行make distclean時系統會把.config文件刪除),以後我們再配置內核時就不需要再去arch/arm/configs下考取相應的文件了,省去了重新配置的麻煩,直接將保存的.config文件復制為.config即可.
5)經過以上兩步,我們可以正確的讀取、配置我們需要的界面了,那麼他們如何跟makefile文件建立編譯關系呢?當你保存make menuconfig選項時,系統會除了會自動更新.config外,還會將所有的選項以宏的形式保存在Linux內核根目錄下的 include/generated/autoconf.h文件下
內核中的源代碼就都會包含以上.h文件,跟宏的定義情況進行條件編譯。
當我們需要對一個文件整體選擇如是否編譯時,還需要修改對應的makefile文件,例如:
我們選擇是否要編譯s3c2410_ts.c這個文件時,makefile會根據CONFIG_TOUCHSCREEN_S3C2410來決定是編譯此文件,此宏是在Kconfig文件中定義,當我們配置完成後,會出現在.config及autconf中,至此,我們就完成了整個linux內核的編譯過程。
最後我們會發現,整個linux內核配置過程中,留給用戶的介面其實只有各層Kconfig、makefile文件以及對應的源文件。
比如我們如果想要給內核增加一個功能,並且通過make menuconfig控制其聲稱過程
首先需要做的工作是:修改對應目錄下的Kconfig文件,按照Kconfig語法增加對應的選項;
其次執行make menuconfig選擇編譯進內核或者不編譯進內核,或者編譯為模塊,.config文件和autoconf.h文件會自動生成;
最後修改對應目錄下的makefile文件完成編譯選項的添加;
最後的最後執行make命令進行編譯。
Kconfig和Makefile
Linux內核源碼樹的每個目錄下都有兩個文檔Kconfig和Makefile。分布到各目錄的Kconfig構成了一個分布式的內核配置資料庫,每個Kconfig分別描述了所屬目錄源文檔相關的內核配置菜單。在執行內核配置make menuconfig時,從Kconfig中讀出菜單,用戶選擇後保存到.config的內核配置文檔中。在內核編譯時,主Makefile調用這 個.config,就知道了用戶的選擇。這個內容說明了,Kconfig就是對應著內核的每級配置菜單。
假如要想添加新的驅動到內核的源碼中,要修改Kconfig,這樣就能夠選擇這個驅動,假如想使這個驅動被編譯,則要修改Makefile。添加新 的驅動時需要修改的文檔有兩種(如果添加的只是文件,則只需修改當前層Kconfig和Makefile文件;如果添加的是目錄,則需修改當前層和目錄下 的共一對Kconfig和Makefile)Kconfig和Makefile。要想知道怎麼修改這兩種文檔,就要知道兩種文檔的語法結構,Kconfig的語法參見參考文獻《【linux-2.6.31】kbuild》。
Makefile 文件包含 5 部分:
Makefile 頂層的 Makefile
.config 內核配置文件
arch/$(ARCH)/Makefile 體系結構 Makefile
scripts/Makefile.* 適用於所有 kbuild Makefile 的通用規則等
kbuild Makefiles 大約有 500 個這樣的文件
頂層 Makefile 讀取內核配置操作產生的.config 文件,頂層 Makefile 構建兩個主要的目標:vmlinux(內核映像)和 moles(所有模塊文件)。它通過遞歸訪問內核源碼樹下的子目錄來構建這些目標。訪問哪些子目錄取決於內核配置。頂層 Makefile 包含一個體系結構 Makefile,由 arch/$(ARCH)/Makefile 指定。體系結構 Makefile 文件為頂層 Makefile 提供了特定體系結構的信息。每個子目錄各有一個 kbuild文件和Makefile 文件來執行從上層傳遞下來的命令。kbuild和Makefile文件利用.config 文件中的信息來構造由 kbuild 構建內建或者模塊對象使用的各種文件列表。scripts/Makefile.*包含所有的定義/規則,等等。這些信息用於使用 kbuild和 Makefile 文件來構建內核。Makefile的語法參見參考文獻《【linux-2.6.31】kbuild》。
參考文獻
【linux-2.6.31】內核編譯指南.pdf
【linux-2.6.31】kbuild.pdf
Linker script in Linux.pdf
linux內核的配置機制及其編譯過程
Linux內核編譯過程詳解
Linux Kconfig及Makefile學習
⑦ 嵌入式Linux上的C語言編程實踐的目錄
第一部分 基礎知識
第1章 Linux環境下C語言的開發 2
1.1 Linux下的C語言開發環境 2
1.2 在Linux中使用C語言開發 3
1.2.1 開發流程和開發工具 3
1.2.2 Linux中程序的運行原理 4
第2章 嵌入式環境中的C語言開發 7
2.1 嵌入式C語言的開發環境 7
2.2 嵌入式開發中C語言編程要點 9
第二部分 Linux環境中
C語言的開發環境和工具
第3章 Linux的文本編輯工具VI 12
3.1 VI編輯器概述 12
3.1.1 VI簡介 12
3.1.2 VI的工作模式和使用
3.1.2 之前的准備 12
3.1.3 進入和退出VI 13
3.2 VI的增強版VIM 16
3.3 VI編輯器的基本使用方法 17
3.3.1 在屏幕上移動游標 17
3.3.2 插入文本 20
3.3.3 刪除文本 22
3.3.4 修改文本內容 25
3.3.5 替換文本內容 27
3.3.6 合並文本內容 30
3.3.7 移動文本內容 30
3.4 VI編輯器的命令和高級操作 32
3.4.1 VI常用命令的列表 32
3.4.2 VI的一些高級的操作和
3.1.2 使用技巧 35
第4章 GCC程序開發工具 39
4.1 GNU工具綜述 39
4.2 GCC的編譯和連接 43
4.2.1 工程示例 43
4.2.2 編譯、匯編和連接 46
4.2.3 動態庫 48
4.3 GCC的二進制工具 49
4.3.1 ar(歸檔工具) 49
4.3.2 readelf(讀取ELF格式
3.1.2 文件信息) 51
4.3.3 strings(查看字元串) 54
4.3.4 nm(顯示符號信息) 55
4.3.5 strip(刪除符號) 57
4.3.6 objmp(顯示目標
3.1.2 文件信息) 58
4.3.7 obj(復制目標文件) 63
第5章 make工程管理工具 67
5.1 make和Makefile 67
5.1.1 make機制概述 67
5.1.2 make和Makefile的使用 68
5.2 Makefile使用示例 69
5.2.1 簡單的Makefile 69
5.2.2 Makefile中的依賴關系 71
5.2.3 Makefile中使用隱含規則
3.1.2 來編譯程序 73
5.2.4 Makefile中指定依賴關系的
3.1.2 編譯 76
5.3 自動生成Makefile 78
5.3.1 自動生成Makefile的意義和
3.1.2 相關工具 78
5.3.2 自動生成Makefile的流程 79
第6章 GDB調試工具 85
6.1 GDB簡介 85
6.2 使用GDB調試程序 86
6.2.1 基本操作 88
6.2.2 查看命令 90
6.2.3 高級命令 92
6.2.4 attach命令的使用 94
6.3 遠程GDB調試 95
6.3.1 本地GDB調試和遠程GDB
3.1.2 調試的比較 95
6.3.2 遠程GDB調試流程 97
6.3.3 遠程GDB調試示例 98
第三部分 庫函數
第7章 C語言標准庫函數 106
7.1 ISO的C語言標准庫函數
7.1 分類 106
7.2 標准格式化輸入/輸出類函數 107
7.2.1 scanf函數:格式化輸入
3.1.2 字元串 107
7.2.2 printf函數:格式化輸出
3.1.2 字元串 109
7.2.3 putchar函數:輸出字元到
3.1.2 標准輸出 111
7.2.4 getchar函數:從標准輸入
3.1.2 獲取字元 111
7.2.5 putc函數:向文件輸出字元 112
7.2.6 getc函數:從文件輸入字元 112
7.2.7 gets函數:獲得字元串 112
7.2.8 puts函數:輸出指定字元串 113
7.2.9 ungetc函數:把字元
3.1.2 寫迴流中 113
7.3 字元處理類函數 114
7.4 字元串處理及轉換函數 116
7.4.1 sprintf函數:格式化輸出
3.1.2 字元串到一個緩沖區 116
7.4.2 strcat和strncat函數:
3.1.2 字元串連接 119
7.4.3 strcpy和strncpy函數:
3.1.2 字元串復制 120
7.4.4 strcmp和strncmp函數:
3.1.2 字元串比較 121
7.4.5 strlen函數:獲取字元串
3.1.2 長度 122
7.4.6 strchr和strrchr函數:字元/
3.1.2 字元串定位 122
7.4.7 strstr函數:字元串查找 123
7.4.8 strrev函數:字元串逆序 124
7.4.9 strupr和strlwr函數:字母
3.1.2 形式轉換 125
7.4.10 strp和strnp函數:
3.1.2 字元串復制 125
7.4.11 memset函數:內存設置 126
7.4.12 memmove函數:內存移動 126
7.4.13 memcmp函數:內存比較 127
7.4.14 memcpy函數:內存復制 128
7.5 數學計算類函數 128
7.6 數據結構和演算法類函數 133
7.6.1 bsearch函數:二元搜索 133
7.6.2 lfind函數:線性搜索 134
7.6.3 lsearch函數:線性搜索 135
7.6.4 qsort函數:利用快速排序法
3.1.2 排列數組 136
7.6.5 rand函數:產生隨機數 136
7.6.6 srand函數:設置隨機
3.1.2 數種子 137
7.7 文件I/O操作類相關函數 137
7.7.1 fopen函數:打開文件 138
7.7.2 fclose函數:關閉文件 139
7.7.3 fgetc函數:從文件中讀取
3.1.2 一個字元 139
7.7.4 fputc函數:將一指定字元
3.1.2 寫入文件流中 139
7.7.5 fgets函數:從文件中讀取
3.1.2 一字元串 140
7.7.6 fputs函數:將一指定的
3.1.2 字元串寫入文件內 140
7.7.7 rewind函數:重設文件流的
3.1.2 讀寫位置為文件開頭 141
7.7.8 ftell函數:取得文件流的
3.1.2 讀取位置 141
7.7.9 fseek函數:移動文件流的
3.1.2 讀寫位置 141
7.7.10 fwrite函數:將數據寫至
7.7.10 文件流 142
7.7.11 fread函數:從文件流讀取
7.7.10 數據 142
7.7.12 remove函數:刪除文件 143
7.7.13 rename函數:更改文件
7.7.10 名稱或位置 143
7.7.14 freopen函數:重新打開
7.7.10 文件 144
7.7.15 fflush函數:同步緩沖區 144
7.7.16 fgetpos函數:獲得文件
7.7.10 位置 145
7.7.17 fsetpos函數:設置文件
7.7.10 位置 145
7.7.18 mktemp函數:建立臨時
7.7.10 文件 146
7.7.19 tmpfile函數:臨時文件 146
7.7.20 tmpnam:得到臨時文件名 147
7.8 日期時間類函數 147
7.8.1 clock函數:獲得CPU時間 148
7.8.2 time函數:獲得當前日歷
7.8.2 時間 148
7.8.3 difftime函數:獲得時間
7.8.2 差值 148
7.8.4 gmtime函數:將日歷時間
7.8.2 轉換成UTC時間 149
7.8.5 mktime函數:將UTC時間
7.8.2 轉換成日歷時間 149
7.8.6 asctime函數:將UTC時間
7.8.2 轉換成字元串 149
7.8.7 ctime函數:將日歷時間轉換
7.8.2 成當地時間的字元串 150
7.8.8 localtime函數:將日歷時間
7.8.2 轉換成本地時間 150
7.8.9 strftime函數:轉換日期和
7.8.2 時間格式 151
7.9 國際化和本地化函數 152
7.9.1 setlocale函數:本地化控制
7.8.2 函數 153
7.9.2 localeconv函數:本地化
7.8.2 轉換 154
7.10 錯誤處理類函數 155
7.10.1 clearerr函數:清除流中的
7.10.1 結束指示符和錯誤指示符 155
7.10.2 feof函數:指示文件結束 155
7.10.3 ferror函數:指示文件出錯 156
7.10.4 perror函數:輸出出錯信息 156
7.10.5 errno函數:錯誤編號記錄 156
7.11 其他一些工具函數 157
7.11.1 assert函數:程序診斷 157
7.11.2 長跳轉函數 157
7.11.3 可變長的參數控制函數 160
7.11.4 獲取結構體成員函數
7.10.1 (宏) 161
7.12 一些標准庫中有用的宏 161
第8章 Linux中C語言的擴展庫
函數 163
8.1 文件I/O操作函數 163
8.1.1 open函數:打開文件 163
8.1.2 close函數:關閉文件 164
8.1.3 read函數:讀文件 165
8.1.4 write函數:寫文件 165
8.1.5 lseek函數:文件定位 167
8.1.6 ioctl函數:文件控制 167
8.1.7 flock函數:鎖定文件 167
8.1.8 mmap函數和munmap函數:
8.1.8 內存映射 168
8.1.9 create函數:創建新文件 170
8.1.10 p函數和p2函數:
8.1.10 復制文件描述符 171
8.1.11 fcntl函數:改變已打開的
8.1.10 文件的屬性 171
8.2 文件許可權相關的操作函數 172
8.2.1 access函數:判斷是否
8.2.1 具有存取文件的許可權 172
8.2.2 chown函數和fchown函數:
8.2.1 改變文件的所有者 173
8.2.3 chmod函數和fchmod函數:
8.2.1 改變許可權 173
8.2.4 unlink函數:刪除文件 173
8.2.5 utime函數和utimes函數:
8.2.1 改變文件時間 174
8.2.6 umask函數:設置建立
8.2.1 新文件時的許可權掩碼 175
8.2.7 link函數:建立文件連接 175
8.2.8 stat函數、fstat函數和lstat
8.2.1 函數:獲取文件信息 175
8.3 用戶組操作函數 176
8.3.1 getgid函數和setgid函數:
8.2.1 獲得/設置組識別碼 176
8.3.2 getegid函數和setegid函數:
8.2.1 獲得/設置有效的組識別碼 177
8.3.3 getuid函數和setuid函數:
8.2.1 獲得/設置真實的用戶識別碼 177
8.3.4 geteuid函數和seteuid函數:
8.2.1 獲得/設置有效的用戶識別碼 178
8.3.5 getgroups函數和setgroups
8.2.1 函數:獲得/設置組代碼 178
8.4 信號類函數 179
8.4.1 kill函數:傳送信號給指定的
8.2.1 進程 181
8.4.2 raise函數:信號發送函數 181
8.4.3 alarm函數:設置超時函數 182
8.4.4 signal函數:信號安裝函數 182
8.5 進程處理函數 183
8.5.1 getpid函數和getppid函數:
8.2.1 獲得進程ID和父進程ID 183
8.5.2 fork函數:建立子進程 183
8.5.3 sleep函數和usleep函數:
8.2.1 讓進程暫停執行一段時間 185
8.5.4 exec函數族:找到可執行
8.2.1 文件 185
8.5.5 _ exit函數和_Exit函數:
8.2.1 結束進程執行 188
第四部分 C語言高級編程
第9章 動態內存的堆與棧 190
9.1 程序內存區域的使用 190
9.1.1 靜態內存與動態內存 190
9.1.2 C語言中的動態內存 191
9.2 C程序中棧空間的使用 196
9.2.1 參數使用棧空間 196
9.2.2 自動變數使用棧空間 199
9.2.3 程序中較大的棧 201
9.2.4 棧空間的特性 202
9.3 C程序中的堆空間使用 203
9.3.1 分配和釋放堆內存的庫函數 203
9.3.2 庫函數使用 204
9.3.3 堆內存的特性 218
9.4 堆內存和棧內存使用的比較 222
9.4.1 利用返回值傳遞信息 222
9.4.2 利用參數傳遞信息 226
9.4.3 堆與棧內存管理的區別 231
第10章 函數指針的使用 232
10.1 函數指針的概念 232
10.1.1 C語言函數的本質 232
10.1.2 函數指針在C語言中的
10.1.2 意義 234
10.2 函數指針的使用 237
10.2.1 函數指針使用初步 237
10.2.2 函數指針的類型定義 240
10.2.3 函數指針作為結構體成員 242
10.2.4 函數指針作為函數的參數 243
10.2.5 函數指針作為函數的
10.2.5 返回值 244
10.2.6 函數指針數組 246
10.3 函數指針使用示例 248
第11章 回調函數的使用 252
11.1 回調函數的概念與作用 252
11.1.1 程序調用的方式 252
11.1.2 回調函數的作用 254
11.2 回調函數的語法 254
11.2.1 簡單的回調函數 254
11.2.2 完全形式的回調函數 256
11.3 回調函數的使用 259
11.3.1 qsort中的回調函數 259
11.3.2 atexit和on_exit函數的
10.2.5 注冊退出函數 263
第12章 C語言實現對象編程 268
12.1 C語言實現基於對象編程的
12.1 概念與作用 268
12.2 C語言基於對象編程實現
12.1 封裝 269
12.2.1 簡單的程序示例 269
12.2.2 C語言基於對象編程的
10.2.5 詳解 272
12.2.3 C語言基於對象編程與
10.2.5 C++面向對象編程的對比 275
12.3 C語言基於對象編程實現
12.3 部分繼承功能 278
12.3.1 利用數據結構的包含實現
10.2.5 繼承功能 279
12.3.2 利用私有指針實現繼承
10.2.5 功能 282
12.3.3 C語言實現繼承的總結 287
12.4 C語言基於對象編程實現
12.4 部分多態功能 288
12.4.1 利用操作指針組的包含
10.2.5 實現多態功能 288
12.4.2 C語言實現多態功能的總結 292
12.5 對C語言實現基於對象
12.5 編程的思考 292
12.5.1 C語言基於對象編程的
10.2.5 特性 292
12.5.2 C語言基於對象編程中介面、
10.2.5 實現和調用者的關系 293
第五部分 在嵌入式
環境下的C語言編程
第13章 C語言程序的內存布局 295
13.1 C語言程序的存儲區域 295
13.2 C語言程序的段 297
13.2.1 段的分類 297
13.2.2 程序中段的使用 298
13.3 可執行程序的連接 301
13.3.1 可執行程序的組成 301
13.3.2 各個目標文件的關系 303
13.3.3 連接錯誤示例 304
13.4 C語言程序的運行 309
13.4.1 RAM調試運行 311
13.4.2 固化程序的XIP運行 312
13.4.3 固化程序的載入運行 313
13.4.4 C語言程序的運行總結 315
第14章 嵌入式C語言常用語法 317
14.1 內存指針操作 317
14.1.1 內存操作的意義 317
14.1.2 使用指針操作內存 319
14.1.3 volatile的使用 324
14.1.4 嵌入式系統指針的實際
10.2.5 應用 325
14.2 位操作 327
14.2.1 位操作的意義 327
14.2.2 位操作的語法 328
14.3 大小端與對齊問題 330
14.3.1 大小端問題 331
14.3.2 內存對齊問題 335
14.3.3 結構體成員的對齊問題 338
14.4 程序的跳轉 344
14.4.1 嵌入式系統程序跳轉的
10.2.5 類型 344
14.4.2 C語言中實現程序的跳轉 345
第15章 嵌入式C語言編程的技巧 348
15.1 程序的優化技巧 348
15.1.1 循環緩沖區 348
15.1.2 查表法 350
15.1.3 針對循環執行效率的
10.2.5 優化 353
15.2 關於小數運算 355
15.3 函數參數和返回值的傳遞 357
15.4 變數的初始化技巧 360
15.4.1 數組的初始化 360
15.4.2 結構體的初始化 362
15.4.3 變數的初始化總結 362
15.5 程序的調試和宏使用的技巧 363
15.5.1 列印文件、函數和程序行 363
15.5.2 #:字元串化操作符 364
15.5.3 ##:連接操作符 366
15.5.4 調試宏的第一種定義方式 367
15.5.5 調試宏的第二種定義方式 368
15.5.6 對調試語句進行分級審查 369
15.5.7 條件編譯調試語句 370
15.5.8 使用do…while的宏定義 372
15.6 代碼剖析 373
參考文獻 378
⑧ linux下一個版本,有Makefile,請問,如果分別編譯成debug和release版本,是輸入make -release么
一般,在開發測試階段用debug版本,而上線發布用release版本。
使用Makefile定製編譯不同版本,避免修改程序和Makefile文件,將會十分方便。
讀了一些資料,找到一個解決方法,Makefile預定義宏與條件判斷,結合make預定義變數,進行條件編譯。
比如,有一個test.cpp,包含這段代碼
#ifdef debug
//your code#endif
你希望在debug版本要執行它,在release版本不執行。
我們可以寫這樣的一個Makefile:
1 ver = debug
2
3 ifeq ($(ver), debug)
4 ALL: test_d
5 CXXFLAGS = -c -g -Ddebug
6 else 7 ALL: test_r
8 CXXFLAGS = -c -O3
9 endif
10
11 test_d: test.do12 g++ -o $@ $^
13
14 test_r: test.ro
15 g++ -o $@ $^
16
17 %.do: %.cpp
18 g++ $(CXXFLAGS) $< -o $@
19
20 %.ro: %.cpp
21 g++ $(CXXFLAGS) $< -o $@
簡單說一下,Makefile根據ver的不同定義了不同的編譯選項CXXFLAGS與輸出程序ALL,
debug版本輸出程序是test_d,release版本輸出程序是test_r
debug版本編譯選項是"-c -g -Ddebug",release版本編譯選項是"-c -O3"
debug版本object文件後綴是".do",release版本object文件後綴是".ro"
debug版本編譯選項使用"-D"定義宏debug,使得your code能夠執行。
不同版本的編譯選項、object文件、輸出程序均不同,所以可以同時編譯兩個版本的程序,互不影響。
Makefile執行時,首先判斷ver變數,如果ver的值是debug,編譯debug版,否則編譯release版。當然,默認情況下是編譯debug版的。
如果想編譯release版,要怎麼做?
只要在執行make時,對ver變數賦值,使得ver的值不為debug,比如# make ver=release
⑨ 如何在makefile中定義宏進行條件編譯
你可以藉助BASHSHELL強大的字元串處理能力來實現啊!
比如你可以將你想定義的「宏」放在makefile.include中,然後將其賦值,而在makefile中加入include makefile.include一行,在其後需要進行條件預編譯時進行字元串比較來實現啊!