嵌入式C語言實戰開發詳解(一)
http://blog.csdn.net/wzhcalex/article/details/51874149
一、概述
1、嵌入式開發中爲什麼選擇C語言?
因爲操作系統的內核都是使用的C語言,而且C語言也有如下幾個優點:
(1)出色的移植性,能在多種不同體系結構的軟/硬平臺上運行(修改量越小,移植性越好);
(2)簡潔緊湊,使用靈活的語法機制,並能直接訪問硬件(效率高);
(3)很高的運行效率
拓展:
什麼時候使用匯編什麼時候使用C語言呢?(C VS 彙編)
彙編是低級語言,不能實現複雜的功能,所以:
當對硬件做初始化——彙編
當對硬件做複雜操作——C語言
面向過程處理機制 VS 面向對象處理機制(詳情戳網址)
http://blog.csdn.net/wzhcalex/article/details/51878170
2、嵌入式開發中的地位:
(1)嵌入式Linux應用軟件開發工程設計;
(2)嵌入式Linux驅動開發工程師;
(3)嵌入式BSP開發工程師;
(4)嵌入式Kernel(內核)開發工程師;
3、精通C語言考覈標準:
(1)企業筆試題;
(2)累積的代碼量(強化編程訓練)
(3)良好的編碼規範(華爲的編碼規範要求);
(4)行業應用的項目經驗;
4、如何學習C語言(外功與內功兼修)
(1)零基礎學習經歷過程(菜鳥如何修煉成老鳥)
(2)算法在C語言開發
(3)《C和指針》《C語言專家編程》《程序員的自我修養》《高質量C/C++編程》《編程之美》
5、C語言的標準有哪些?
K&RC、C89、C99、C11
注:
gcc支持的C89,部分兼容C99
不同的編譯器標準不一樣
很多編譯器支持的是C89
二、數據類型
1、什麼是數據類型?
數據集合的劃分,不同的數據類型對CPU的意義是不一樣的。
2、數據類型有哪些?
3、左右法則
右左法則:首先從最裏面的圓括號內未定義的標識符開始閱讀看起,然後往右看,再往左看。每當遇到圓括號時,就應該掉轉閱讀方向。一旦解析完圓括號裏面所有的東西,就跳出圓括號。重複這個過程直到整個聲明解析完畢。
企業筆試題:
1、用變量a給出下列定義
a) 一個整型數(An integer):int a;
b) 一個指向整型數的指針(A pointer to an integer):int *a;
c) 一個指向指針的的指針,它指向的指針是指向一個整型數(A pointer to a
pointer to an integer):int **a;
d) 一個有10個整型數的數組(An array of 10 integers):int a[10];
e) 一個有 10 個指針的數組,該指針是指向一個整型數的(An array of 10
pointers to integers):int *a[10];
f) 一個指向有10個整型數數組的指針(A pointer to an array of 10 integers):
int (*a)[10];
g) 一個指向函數的指針,該函數有一個整型參數並返回一個整型數(A pointer
to a function that takes an integer as an argument and returns an integer):
int (*a)(int);
h) 一個有10個指針的數組,該指針指向一個函數,該函數有一個整型參數並返
回一個整型數( An array of ten pointers to functions that take an integer
argument and return an integer ): int (*a[10])(int).
2、int *(*(*fpl)(int))[10];
fpl:函數指針變量,該函數指針指向一個形參爲int,返回值爲數組指針,該數組指針指向一個整型指針;
int *(*(*arr[5])())();
arr:函數指針數組,該數組裏的元素指向一個形參爲空,返回值爲函數指針的函數,該函數指針指向一個形參爲空,返回值爲整型的指針。
float (*(*b())[ ])();
b:函數,形參爲空,返回值爲數組指針,該指針指向一個函數指針數組,該數組裏的元素指向一個形參爲空,返回值爲float的函數。
void* (*c)(char, int(*)());
c:函數指針變量,該函數指針指向一個形參爲char 、函數指針,返回值爲void*,該函數指針的形參爲空,返回值爲int。
void** (*d)(int *,char **(*)(char *,char **));
d:函數指針變量,指向函數形參爲char,函數指針,返回值爲void **,該函數指針形參爲 char*,char**,返回值爲char**;
float(*(*e[10])(int *))[5];
e:函數指針數組,指向函數形參爲 int *,返回值爲數組指針,該數組元素指向float;
4、隱式類型轉化與強制類型轉化:
char < int < float < double 隱式類型轉化(自動)
代碼示例:
這就是隱式類型轉換;
強制類型轉化:
代碼示例:
5、數據類型的重要知識點:
字節長度:
bit;
字節 = 8bit;
半字 = 2個字節 = 16bit;
字 = 4個字節 = 32;
6、基本數據類型
char 1個字節;
short 2個字節;
int 4個字節;
long 4個字節;
float 4個字節;
double 8個字節;
long long 8個字節;
代碼查詢:
拓展:
爲什麼任何類型的指針都是4字節?
因爲指針指向地址,地址長度都是固定的。而地址長度是由操作系統決定,如果操作系統是32位的,地址長度爲4字節;如果操作系統是64位的,則地址長度爲8字節。
char 取值範圍:
無符號:0~255(2^8-1)
有符號:-128~127
有符號時:第一個爲符號位:
0爲整數:0 000 0000 = 0; 0 111 1111 = 127;
1爲負數:負數時計算機保存補碼
1 000 0000 取反加1 = -128
1 111 1111 取反加1 = -1
補碼取反加1成原碼
例如:
打印~2:常量都是有符號的:0 000 0010
取反:1 111 1101 負值
取反加1:0 000 0011 = -3
代碼舉例:
分析:-128 1 000 0000
取反 1 111 1111
加1 0 111 1111 = 127
企業筆試題:
輸出結果分析:
有符號:i = 127 a[127] = -128
i = 128 a[128] = 127
...
i = 255 a[255] = 0; 0 相當於‘\0’
strlen(a)統計到‘\0’跳出,共255個。
無符號:i = 0 a[0] = 255;
i = 1 a[1] = 254;
...
i = 255 a[255] = 0;
strlen(a)統計到‘\0’跳出,共255個。
有符號與無符號數據的區別:
實例解析:
分析:
有符號數和無符號數進行比較運算時(==、<、>、<=、>=)有符號數隱式轉換成了無符號數(即底層的補碼)但是此數從有符號數變成了無符號數。
7、sizeof與strlen區別(詳情請戳網址):
http://blog.csdn.net/wzhcalex/article/details/51852632
8、變量與常量
變量三大特點:
變量的數據類型:主要說明變量佔用的內存空間的大小,如 int型;
變量的作用域:變量的有效性範圍,如變量的使用範圍;
變量的存儲類別:變量在內存中的存儲方式,不同的存儲方式影響變量在內存中的生存週期。
MMU:虛擬地址單元 解決內存資源稀缺問題
(打印一個地址:打印的都是虛擬的地址)
爲了保護數據的安全,操作系統會對空間做劃分:
棧空間:局部變量、函數形參、自動變量(調用後釋放)
特點:先進後出,管理權限:系統
堆空間:malloc、ralloc、calloc 分配空間
特點:先進先出,管理權限:用戶
數據段:bss:保存未初始化的全局變量
rodata:常量
.data(靜態數據區):全局變量(程序結束後釋放)、static 修飾變量
全局變量與局部變量的區別:
(主要從空間的分配,沒有初始化的值 什麼時候釋放等角度入手)
9、聲明與定義:
聲明:不分配內存空間,可以聲明多次;
定義:分配內存空間,只可以定義一次。
變量的聲明有兩種情況:
定義性聲明:需要建立存儲空間的,例如:int a在聲明時就已經建立了存儲空間;
引用性聲明:不需要建立存儲空間, 例如:extern int a 其中變量a是在別的文件中定義的。
10、格式化輸出與輸入:
首先,通過代碼來示例以下不同的數據類型的不同的輸入輸出方法:
運行結果:
在獲取字符是用一個getchar()清空緩存區
以下是getchar()的作用(轉自網絡):
1.從緩衝區讀走一個字符,相當於清除緩衝區
2.前面的scanf()在讀取輸入時會在緩衝區中留下一個字符'\n'(輸入完s[i]的值後按回車鍵所致),所以如果不在此加一個getchar()把
這個回車符取走的話,gets()就不會等待從鍵盤鍵入字符,而是會直接取走這個“無用的”回車符,從而導致讀取有誤
3. getchar()是在輸入緩衝區順序讀入一個字符(包括空格、回車和Tab) getchar()使用不方便,解決方法:
(1)使用下面的語句清除回車: while(getchar()!='\n');
(2)用getche()或getch()代替getchar(),其作用是從鍵盤讀入一個字符(不用按回車),注意要包含頭文件<conio.h>
三種獲得字符串的方法:scanf gets getchar
scanf 與 gets 的區別(以下轉自網絡):
gets(s)函數與 scanf("%s",&s) 相似,但不完全相同,使用scanf("%s",&s) 函數輸入字符串時存在一個問題,就是如果輸入了空格會認
爲字符串結束,空格後的字符將作爲下一個輸入項處理,但gets()函數將接收輸入的整個字符串直到遇到換行爲止。
1.scanf() 所在頭文件:stdio.h
語法:scanf("格式控制字符串",變量地址列表);
接受字符串時:scanf("%s",字符數組名或指針);
2.gets() 所在頭文件:stdio.h
語法:gets(字符數組名或指針);
兩者在接受字符串時:
1.不同點: scanf不能接受空格、製表符Tab、回車等; 而gets能夠接受空格、製表符Tab和回車等;
2.相同點: 字符串接受結束後自動加'\0'。
使用gets獲取字符串代碼:
如何讓scanf不遇到空格結束呢?
在%前面加空格
詳情請戳網址:http://blog.csdn.net/mishifangxiangdefeng/article/details/7163002
(技術大牛寫的帖)
獲取數組方法:
1、
3、
第一版本代碼中
不可以用a++ 是因爲a是常量不可以自加,*p = a 指針可以自加 p++
printf是行緩衝,我們用以下代碼驗證:
1、
2、
3、
4、