嵌入式C語言實戰開發詳解(一)

嵌入式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  隱式類型轉化(自動)


代碼示例:



這就是隱式類型轉換;


強制類型轉化:

代碼示例:




上述代碼中的char*就是強制類型轉化


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、格式化輸出與輸入:

首先,通過代碼來示例以下不同的數據類型的不同的輸入輸出方法:

[html] view plain copy
  1. #include<stdio.h>  
  2.   
  3. int main()  
  4. {  
  5.     int i;  
  6.   
  7.     int num;  
  8.   
  9.     char ch;  
  10.   
  11.     float f_num;  
  12.   
  13.     double d_num;  
  14.   
  15.     int a[3];  
  16.   
  17.     char src[100];  
  18.   
  19.     scanf("%d",&num);  
  20.     printf("num = %d\n",num);  
  21.   
  22.     getchar();  
  23.     scanf("%c",&ch);  
  24.     printf("ch = %c\n",ch);  
  25.   
  26.     scanf("%f",&f_num);  
  27.     printf("f_num = %f\n",f_num);  
  28.   
  29.     scanf("%lf",&d_num);  
  30.     printf("d_num = %lf\n",d_num);  
  31.   
  32.     printf("please input a[3]:\n");  
  33.     for(i = 0; i < 3; i++)  
  34.     {  
  35.         scanf("%d",&a[i]);  
  36.     }  
  37.     for(i = 0; i < 3; i++)  
  38.     {  
  39.         printf("a[%d] = %d\n",i,a[i]);  
  40.     }  
  41.   
  42.     scanf("%s",src);  
  43.     printf("src[100] = %s\n",src);  
  44.   
  45.     return 0;  
  46. }  
運行結果:



在獲取字符是用一個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獲取字符串代碼:

[html] view plain copy
  1. #include<stdio.h>  
  2.   
  3. int main()  
  4. {  
  5.     char src[100];  
  6.   
  7.     printf("input a string:");  
  8.     gets(src);  
  9.   
  10.     printf("src = %s\n",src);  
  11.   
  12.   
  13.     return 0;  
  14. }  


使用getchar()獲取字符串:

[html] view plain copy
  1. #include<stdio.h>  
  2.   
  3. int main()  
  4. {  
  5.     char ch;  
  6.     char src[10];  
  7.   
  8.     int i = 0;  
  9.   
  10.     while((ch = getchar()) != '\n')  
  11.     {  
  12.         src[i] = ch;  
  13.     i++;  
  14.   
  15.     if(i == 9)  
  16.     {  
  17.          printf("error!\n");  
  18.          exit(1);  
  19.     }  
  20.   
  21.     src[i] = '\0';  
  22.       
  23.     }  
  24.   
  25.     return 0;  
  26. }  



如何讓scanf不遇到空格結束呢?

在%前面加空格 

詳情請戳網址:http://blog.csdn.net/mishifangxiangdefeng/article/details/7163002

(技術大牛寫的帖)


獲取數組方法:

1、

[html] view plain copy
  1. #include<stdio.h>  
  2.   
  3. int main()  
  4. {  
  5.     int a[3];  
  6.     int i;  
  7.     int *p = a;  
  8.   
  9.     for(i = 0; i <= 2; i++)  
  10.     {  
  11.         scanf("%d",p++);  
  12.     }  
  13.   
  14.     p = a;  
  15.   
  16.     for(i = 0;i < 3; i++)  
  17.     {  
  18.         printf("a[%d] = %d\n",i,*(p + i));  
  19.     }  
  20.           
  21.     return 0;  
  22.   
  23. }  
[html] view plain copy
  1. </pre><pre name="code" class="html">2、  
[html] view plain copy
  1. #include<stdio.h>  
  2.   
  3. int main()  
  4. {  
  5.     int a[3];  
  6.     int i;  
  7.       
  8.     for(i = 0; i <= 2; i++)  
  9.     {  
  10.         scanf("%d",&a[i]);  
  11.     }  
  12.   
  13.     p = a;  
  14.   
  15.     for(i = 0;i < 3; i++)  
  16.     {  
  17.         printf("a[%d] = %d\n",i,a[i]);  
  18.     }  
  19.           
  20.     return 0;  
  21.   
  22. }  
3、

[html] view plain copy
  1. #include<stdio.h>  
  2.   
  3. int main()  
  4. {  
  5.     int a[3];  
  6.     int i;  
  7.      
  8.     for(i = 0; i <= 2; i++)  
  9.     {  
  10.         scanf("%d",a+i);  
  11.     }  
  12.   
  13.     p = a;  
  14.   
  15.     for(i = 0;i < 3; i++)  
  16.     {  
  17.         printf("a[%d] = %d\n",i,*(a + i));  
  18.     }  
  19.           
  20.     return 0;  
  21.   
  22. }  

第一版本代碼中
[html] view plain copy
  1. scanf("%d",p++);  

不可以用a++ 是因爲a是常量不可以自加,*p = a 指針可以自加 p++


printf是行緩衝,我們用以下代碼驗證:

1、




2、




3、




4、




發佈了7 篇原創文章 · 獲贊 139 · 訪問量 38萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章