內容簡介
本書從嵌入式開發角度出發,以Linux作業系統為開發平台,將隱藏在系統開發背後的關於C語言、數據結構與算法、計算機組成原理、計算機作業系統、資料庫原理等方面的機制和知識娓娓道來,不僅讓讀者知其然,更要讓讀者知其所以然,並讓這些知識再反作用於編程實踐,從而幫助讀者寫出高質量的嵌入式Linux C代碼,揭開嵌入式Linux C系統開發背後鮮為人知的秘密。
圖書目錄
第 1 章 嵌入式Linux C 語言開發工具(1)
1.1 嵌入式Linux C 語言開發概述(1)
1.2 嵌入式Linux C 開發環境(2)
1.3 嵌入式文本編輯器(2)
1.3.1 基本模式. (3)
1.3.2 基本操作(3)
1.3.3 實訓操作(5)
1.4 嵌入式編譯器(6)
1.4.1 初識GCC 編譯器(6)
1.4.2 gcc 命令常用選項和工作流程(6)
1.4.3 庫的使用.(10)
1.5 嵌入式調試器.(12)
1.6 工程管理器.(15)
1.6.1 Makefile.(16)
1.6.2 Makefile 特性介紹.(18)
1.7 Eclipse 程式開發.(27)
1.7.1 Eclipse 環境安裝.(27)
1.7.2 Eclipse C 程式開發.(29)
1.8 軟體版本管理.(34)
1.8.1 Git 版本管理.(34)
1.8.2 Ubuntu 軟體包管理.(45)
第 2 章 數據類型.(48)
2.1 變數與常量.(48)
2.2 變數.(48)
2.2.1 什麼是變數.(48)
2.2.2 變數名和變數值.(49)
2.2.3 局部變數和全局變數.(51)
2.3 常量.(53)
2.4 基本內置類型.(54)
2.4.1 數據類型及其大小.(55)
2.4.2 陷阱——有符號與無符號.(55)
2.5 聲明與定義.(56)
2.5.1 定義.(56)
2.5.2 聲明.(57)
2.6 static 與extern.(57)
2.6.1 static .(57)
2.6.2 extern ...(59)
2.7 const .(60)
2.8 auto.(61)
2.9 register.(62)
2.10 volatile .(63)
2.11 typedef 詳解.(64)
2.11.1 typedef 與結構的問題.(64)
2.11.2 typedef 與#define 的問題.(66)
2.11.3 typedef 與#define 的另一例.(67)
2.11.4 typedef 與複雜的變數聲明.(67)
2.12 枚舉(enum).(68)
2.12.1 枚舉類型的使用方法.(68)
2.12.2 枚舉與#define 宏的區別.(69)
2.13 聯合體.(69)
2.13.1 聯合體的定義.(69)
2.13.2 從兩道經典試題談聯合體(union)的使用.(70)
第 3 章 運算符和表達式(73)
3.1 運算符簡介.(73)
3.1.1 運算符優先權.(73)
3.1.2 一些容易出錯的優先權問題.(75)
3.1.3 邏輯運算符.(76)
3.2 條件運算符和條件表達式.(76)
3.3 ++、--操作符.(77)
3.4 位運算.(78)
3.4.1 按位與運算及套用.(78)
3.4.2 按位或運算及套用.(79)
3.4.3 按位異或運算及套用.(79)
3.4.4 左移和右移.(79)
3.5 C 語言性能最佳化:使用位操作.(79)
第 4 章 語句.(81)
4.1 空語句.(81)
4.2 基礎語句.(82)
4.2.1 表達式語句. (82)
4.2.2 函式調用語句.(82)
4.3 if 語句.(82)
4.3.1 布爾變數與零值的比較.(83)
4.3.2 整型變數與零值比較.(83)
4.3.3 浮點變數與零值的比較.(83)
4.3.4 指針變數與零值的比較.(84)
4.3.5 對if 語句的補充說明.(84)
4.4 跳轉語句:goto .(85)
4.5 循環語句.(85)
4.5.1 do-while 語句.(86)
4.5.2 for 語句.(86)
4.5.3 循環語句的效率.(88)
4.6 break 和continue .(89)
4.6.1 break 語句.(89)
4.6.2 continue 語句.(90)
4.7 switch 語句.(91)
第 5 章 數組與指針.(92)
5.1 數組認知.(92)
5.2 使用數組的常見問題.(93)
5.2.1 數組的下標總是從0 開始嗎. .(93)
5.2.2 可以使用數組後面第一個元素的地址嗎. .(94)
5.2.3 為什麼要小心對待位於數組後面的那些元素的地址呢.(95)
5.2.4 當數組作為參數傳遞給函式時,可以通過sizeof 得到數組的大小嗎.(95)
5.2.5 指針或帶下標的數組名都可以訪問元素,哪一種更好呢.····(96)
5.2.6 可以把另外一個地址賦給一個數組名嗎(98)
5.2.7 array_name 和&array_name 有什麼不同.(99)
5.2.8 為什麼用const 說明的常量不能用來定義一個數組的初始大小(100)
5.2.9 字元串和數組有什麼不同(100)
5.3 指針(102)
5.3.1 指針是變數(103)
5.3.2 指針的類型和指針所指向的類型(103)
5.3.3 指針的值(104)
5.3.4 指針本身所占據的記憶體(105)
5.4 指針的運算(105)
5.4.1 指針的算術運算(105)
5.4.2 指針的關係運算(106)
5.4.3 間接引用(106)
5.4.4 最多可以使用幾層指針(106)
5.5 常量指針和指針常量(108)
5.5.1 常量指針與指針常量的實例(108)
5.5.2 常量指針的套用(109)
5.6 空指針及其使用(110)
5.6.1 NULL 總是被定義為0 嗎(110)
5.6.2 NULL 總是等於0 嗎(110)
5.6.3 空指針的使用(111)
5.7 void 指針:萬能指針(113)
5.8 指針數組與數組指針(114)
5.9 字元串函式詳解(114)
5.10 函式指針與指針函式(119)
5.11 複雜指針聲明:“int * (* (*fp1) (int) ) [10];” (120)
5.11.1 基礎(120)
5.11.2 const 修飾符(121)
5.11.3 typedef 的妙用(122)
5.11.4 函式指針(123)
5.11.5 右左法則(123)
第 6 章 記憶體管理(125)
6.1 數據放在哪裡(125)
6.1.1 未初始化的全局變數(.bss 段) (125)
6.1.2 初始化過的全局變數(.data 段) (126)
6.1.3 常量數據(.rodata 段) (126)
6.1.4 代碼(.text 段) (127)
6.1.5 棧(stack) (127)
6.1.6 堆(heap)(127)
6.2 記憶體分配方式(128)
6.3 野指針(129)
6.4 常見的記憶體錯誤及對策(129)
6.5 段錯誤及其調試方法(130)
6.5.1 方法一:利用gdb 逐步查找段錯誤(131)
6.5.2 方法二:分析core 檔案(131)
6.5.3 方法三:在發生段錯誤時啟動調試(132)
6.5.4 方法四:利用backtrace 和objdump 進行分析(134)
6.6 指針與數組的對比(135)
第 7 章 預處理和結構體(138)
7.1 宏定義:#define(138)
7.1.1 無參宏定義(138)
7.1.2 帶參宏定義(140)
7.2 檔案包含(141)
7.3 條件編譯(142)
7.4 宏定義的使用技巧(144)
7.5 關於#和## (146)
7.6 結構體(struct) (147)
7.6.1 記憶體位元組對齊(149)
7.6.2 記憶體對齊的正式原則(152)
7.7 #define 和typedef 的區別(152)
7.8 結構體(struct)和聯合體(union)的區別(153)
7.9 淺談C 語言中的位段(153)
7.9.1 位段的使用(154)
7.9.2 位段結構在記憶體中的存儲方式(154)
第 8 章 函式(155)
8.1 函式聲明與定義(155)
8.1.1 定義(155)
8.1.2 聲明與定義不同(156)
8.2 形式參數和實際參數(157)
8.3 參數傳遞(157)
8.3.1 簡單變數或數組元素作為函式參數(157)
8.3.2 指針變數或數組名作為函式參數(158)
8.3.3 數組名作為函式參數(159)
8.3.4 結構體數組作為函式參數(160)
8.4 如何編寫有多個返回值的C 語言函式(160)
8.4.1 利用全局變數(161)
8.4.2 傳遞數組指針(162)
8.4.3 傳遞結構體指針(162)
8.5 回調函式(163)
8.6 變參函式詳解:printf 函式的實現(165)
8.7 可變參數的相關問題(166)
第 9 章 編碼規範(170)
9.1 排版(170)
9.2 注釋(173)
9.3 標示符名稱(178)
第 10 章 shell 編程(181)
10.1 什麼是shell (181)
10.2 幾種流行的shell (181)
10.3 shell 程式設計(基礎部分) (182)
10.3.1 shell 的基本語法(182)
10.3.2 shell 程式的變數和參數(183)
10.4 shell 程式設計的流程控制(185)
10.4.1 test 命令(185)
10.4.2 if 條件語句(186)
10.4.3 for 循環(187)
10.4.4 while 和until 循環(187)
10.4.5 case 條件選擇(189)
10.4.6 無條件控制語句break 和continue(189)
10.4.7 函式定義(189)
10.5 命令分組(190)
10.6 用trap 命令捕捉信號(190)
10.7 運行shell 程式的方法(191)
10.8 bash 程式的調試(191)
10.9 bash 的內部命令(192)
第 11 章 檔案操作(194)
11.1 Linux 檔案結構(194)
11.1.1 Linux 檔案系統(194)
11.1.2 Linux 目錄結構(195)
11.1.3 Linux 檔案分類(197)
11.1.4 常見的檔案類型(198)
11.1.5 Linux 檔案屬性(198)
11.2 系統調用(198)
11.3 Linux 檔案描述符(199)
11.4 不帶快取的I/O 操作(200)
11.4.1 creat 函式(200)
11.4.2 open 函式(201)
11.4.3 read 函式(203)
11.4.4 write 函式(204)
11.4.5 lseek 函式(204)
11.4.6 close 函式(205)
11.4.7 經典範例:檔案複製(205)
11.5 帶快取的I/O 操作(207)
11.5.1 3 種類型的緩衝(207)
11.5.2 fopen 函式(209)
11.5.3 fclose 函式(209)
11.5.4 fdopen 函式(210)
11.5.5 fread 函式(210)
11.5.6 fwrite 函式(211)
11.5.7 fseek 函式(212)
11.5.8 fgetc 函式、getc 函式和getchar 函式(213)
11.5.9 fputc 函式、putc 函式和putchar 函式(214)
11.6 fgets 函式與gets 函式的比較分析(215)
11.7 輸出與輸入(217)
11.7.1 printf 函式、fprintf 函式和sprintf 函式(217)
11.7.2 scanf 函式、fcanf 函式和sscanf 函式(220)
第12 章 進程控制編程(222)
12.1 為何需要多進程(或者多執行緒),為何需要並發(222)
12.1.1 進程(222)
12.1.2 進程分類(223)
12.1.3 進程的屬性(223)
12.1.4 父進程和子進程(223)
12.2 Linux 進程管理(224)
12.2.1 ps 監視進程工具(224)
12.2.2 pgrep 查詢進程工具(226)
12.2.3 終止進程的工具kill、killall、pkill 和xkill(226)
12.2.4 top 監視系統任務的工具(228)
12.2.5 進程的優先權:nice 和renice (229)
12.3 Linux 進程的三態(230)
12.3.1 三種基本狀態(230)
12.3.2 三種狀態間的轉換(231)
12.4 Linux 進程結構(231)
12.5 Linux 進程控制塊PCB (232)
12.6 Linux 進程調度(233)
12.6.1 調度的目標(233)
12.6.2 調度算法(233)
12.6.3 優先權反轉(235)
12.7 進程創建(236)
12.7.1 獲取進程(236)
12.7.2 啟動進程:fork( ) (237)
12.7.3 啟動進程:vfork( )(240)
12.7.4 啟動進程:exec 族(241)
12.7.5 啟動進程:system(244)
12.8 進程等待(245)
12.8.1 殭屍進程的產生(245)
12.8.2 如何避免殭屍進程(247)
12.8.3 wait 函式和waitpid 函式(247)
12.9 進程退出(251)
12.9.1 退出方式的不同點(252)
12.9.2 exit 函式和_exit 函式(252)
12.9.3 exit 函式和_exit 函式的區別(253)
12.10 守護進程(253)
12.10.1 守護進程概述(253)
12.10.2 守護進程的創建(254)
12.10.3 創建守護進程的一般步驟(254)
12.10.4 利用庫函式daemon 創建守護進程(258)
第 13 章 進程間通信方式(260)
13.1 進程間通信方式概述(260)
13.1.1 進程間通信的目的(260)
13.1.2 Linux 進程間通信方式簡介(261)
13.2 管道通信(262)
13.2.1 創建無名管道(262)
13.2.2 讀寫無名管道(263)
13.2.3 無名管道套用實例(267)
13.2.4 創建有名管道(269)
13.2.5 讀寫有名管道(271)
13.3 管道通信方式的套用場景(274)
13.4 信號(275)
13.4.1 信號及信號來源(275)
13.4.2 信號種類(275)
13.4.3 信號處理方式(277)
13.4.4 信號傳送(277)
13.4.5 自定義信號處理方式(279)
13.4.6 信號集操作(284)
13.4.7 使用信號注意事項(285)
13.5 訊息佇列(287)
13.5.1 訊息佇列基礎理論(287)
13.5.2 使用訊息佇列(288)
13.5.3 訊息佇列API (289)
13.5.4 訊息佇列的限制(292)
13.5.5 訊息佇列的套用實例(292)
13.6 信號燈(295)
13.6.1 信號燈概述(295)
13.6.2 核心實現原理(296)
13.6.3 使用信號燈(296)
13.6.4 信號燈API (297)
13.6.5 信號燈的限制(299)
13.6.6 競爭問題(299)
13.6.7 信號燈套用實例(300)
13.7 共享記憶體方式一(303)
13.7.1 核心實現原理(304)
13.7.2 mmap( )及其相關係統調用(304)
13.7.3 mmap( )範例(306)
13.7.4 對mmap( )返回地址的訪問(310)
13.8 共享記憶體方式二(312)
13.8.1 系統V 共享記憶體原理(312)
13.8.2 系統V 共享記憶體API(314)
13.8.3 系統V 共享記憶體範例(314)
第 14 章 多執行緒編程(318)
14.1 執行緒概述(318)
14.1.1 為什麼有了進程的概念後,還要再引入執行緒呢(318)
14.1.2 多執行緒的優點(319)
14.1.3 多執行緒的缺點(319)
14.2 多執行緒的實現(320)
14.2.1 執行緒的創建(320)
14.2.2 終止執行緒(322)
14.2.3 等待執行緒終止(323)
14.3 執行緒屬性(324)
14.3.1 執行緒屬性初始化(324)
14.3.2 執行緒分離(325)
14.3.3 執行緒的繼承性(326)
14.3.4 執行緒的調度策略(327)
14.3.5 執行緒的調度參數(327)
14.3.6 實例分析(329)
14.4 執行緒同步機制(330)
14.4.1 互斥鎖(Mutex) (330)
14.4.2 互斥鎖使用實例(332)
14.4.3 條件變數(Conditions)(333)
14.4.4 條件變數使用實例(335)
第 15 章 網路編程(337)
15.1 TCP/IP 協定概述(337)
15.1.1 TCP/IP 協定的起源(337)
15.1.2 TCP/IP 協定的特性與套用(338)
15.1.3 網際網路地址(339)
15.1.4 域名系統(340)
15.1.5 封裝(340)
15.1.6 TCP/IP 協定的工作模型(341)
15.1.7 TCP/IP 協定層(342)
15.1.8 TCP/IP 協定的套用(343)
15.1.9 網橋、路由器和網關(344)
15.2 TCP 和UDP (345)
15.2.1 TCP (345)
15.2.2 三次握手(346)
15.2.3 TCP 數據報頭(347)
15.2.4 UDP (348)
15.2.5 協定的選擇(348)
15.2.6 連線埠號和IP 地址(348)
15.3 套接字(349)
15.3.1 Socket 的概念(349)
15.3.2 Socket 的類型(349)
15.3.3 Socket 的信息數據結構(349)
15.3.4 數據存儲優先順序的轉換(350)
15.3.5 地址格式轉化(351)
15.3.6 名字地址轉化(352)
15.4 網路編程(355)
15.4.1 建立Socket 通信(355)
15.4.2 綁定地址(356)
15.4.3 監聽(358)
15.4.4 接受請求(358)
15.4.5 連線伺服器(359)
15.4.6 傳送數據(360)
15.4.7 接收數據(362)
15.5 採用TCP 協定的C/S 架構實現(363)
15.5.1 模組封裝(363)
15.5.2 伺服器端的實現(365)
15.5.3 客戶端的實現(366)
15.6 並發伺服器模型(367)
15.6.1 多進程解決方案(367)
15.6.2 多執行緒解決方案(368)
15.6.3 調用fcntl 將sockfd 設定為非阻塞模式(374)
15.7 多路轉接模型.(374)
15.7.1 伺服器端的實現(375)
15.7.2 客戶端的實現(379)
15.8 採用UDP 的C/S 架構的實現(381)
15.8.1 伺服器端的實現(381)
15.8.2 客戶端的實現(382)
15.8.3 UDP 傳輸檔案的實現(383)
第 16 章 SQLite3 資料庫編程(386)
16.1 SQLite 資料庫簡介(386)
16.2 SQLite3 的命令(387)
16.3 SQLite 編程接口(389)
16.3.1 資料庫的打開與關閉(389)
16.3.2 資料庫的語句執行(390)
16.3.3 資料庫查詢語句操作(391)
第 17 章 高性能伺服器設計(395)
17.1 select 系統調用(395)
17.1.1 select API(395)
17.1.2 fd_set(396)
17.1.3 檔案描述符就緒條件(397)
17.1.4 select 實現TCP 循環伺服器案例分析(397)
17.2 poll 系統調用(400)
17.2.1 poll API(400)
17.2.2 poll 函式的事件標識符(400)
17.2.3 返回值和錯誤代碼(401)
17.2.4 poll 實現TCP 循環伺服器案例分析(401)
17.3 epoll 系列系統調用(404)
17.3.1 select 的缺陷(404)
17.3.2 核心事件表(405)
17.3.3 epoll_wait 函式(405)
17.3.4 LT 模式和ET 模式(406)
17.4 xinetd 配置(406)
17.4.1 Linux 守護進程(406)
17.4.2 超級服務xinetd(407)
17.4.3 xinetd 配置檔案(407)
參考文獻(409)