嵌入式基础之----C语言
? ?一:數據類型
●枚舉類型??(整形數據的集合)
聲明舉例:?enum?DAY{?mon=1?,?tue?,?wen?,?thu?,?tue?,?fri?,?sat?,??
????????????????????sun?};
???????????enum?DAY?today?,?tomorrow?;
????或者???enum?DAY{?mon?=1,?tue?,?wen?,?thu?,?tue?,?fri?,?sat?,
????????????????????sun?}today?,?tomorrow?;
????或者???enum????{?mon?=1,?tue?,?wen?,?thu?,?tue?,?fri?,?sat?,
????????????????????sun?}today?,?tomorrow?;
????或者???typedef??enum?DAY{?mon?=1,?tue?,?wen?,?thu?,?tue?,?fri?,???????????????????????????
?????????????????????????????sat?,??sun?}?Day;
????????????Day?today,tomorrow;
????或者???typedef??enum?{?mon?=1,?tue?,?wen?,?thu?,?tue?,?fri?,???????????????????????????
??????????????????????????sat?,??sun?}?Day;
????????????Day?today,tomorrow;
·枚舉類型的默認初始化規則?,第一個變量為?0?;后一個比前一個大?1.
·枚舉值是常量,不是變量。不能在程序中用賦值語句再對它賦值。
·枚舉的使用??比如:?today?=?mon;?tomorrow?=?tue;
·疑問:1?若只對枚舉進行部分初始化,其余值的默認初始化是怎么樣的?
????????2?如果是自動型的枚舉,其初始化是怎么樣的?
????????3?對于上述的today?或者?tomorrow?沒有初始化賦值,其默認值是
??????????什么樣的呢,如果是自動變量,結果又是如何?
·解惑:1?枚舉的初始化可以看做兩部分,一是枚舉內部的符號常量的初始
??????????化。始終是符合如下規律的“若第一個符號常量沒有被賦值初始
??????????化,那么它被默認初始化為0;?若非第一個符號常量未被賦值初?
??????????始化,那么它的默認初始化值始終比它左邊的一個符號常量大?
??????????1”.?而對于?像?today?或者?tomorrow?這樣的枚舉變量,如果沒
??????????有賦值初始化。若是全局變量,那么它被初始化為0;局部變量,
??????????被初始化為隨機。
??????????2:對于局部變量,那么枚舉內部的初始化規則不會變,但是枚舉變
??????????量本身,就會被賦予垃圾(隨機數)
??????????3:見1和2的回答
●字符串常量。?記住無論什么時候看到字符串常量,那么它的直接值就是一個
地址。不過有一種情況,表面上看上去是一個字符串常量,但是它的直接值不是一個地址,那就是在字符數組的初始化中。比如?char?a[10]={"hello!"};?不過要記住,這只是表面看上去像,實際上它是??char?a[10]={'h','e','l','l','o','!'}的另外一種簡化表述而已,不應該被看做是字符串常量。
·疑問:當對一個字符數組進行如下初始化之后?char?a[10]={'h','e','l','l','o','!'}
或者?char?a[10]={"hello!"};?其'!'字符之后有沒有'\0'結束符呢?
·解惑:?
???????對于數組,首先要明白一點,如果部分初始化了,那么其余部分會被編譯器初始化為0,也就是全部都是'\0'符。而對于沒有一點初始化過的數組,如果是全局變量,那么它所有的項都會被初始化為0?。?但如果是局部的變量,那么它是不會被初始化的!!另外對于全部被程序員初始化滿的數組,那么在數組后面得內存是不會被自動賦0的。但是如果是全局變量,一般來說它的后面很可能會是沒有動過的內存,也就是0.但對于局部變量,如果它全部被初始化滿了,那么它后面的內存很可能是非0的。另外,如果雖然是局部變量,但被聲明為靜態的,那么它的性質就和全局變量是一樣的!!
●變量的作用域。
????四種作用域:文件作用域,函數作用域,代碼塊作用域和函數原型作用域。
任何在所有代碼塊外面聲明的變量具有文件作用域。主要掌握文件作用域和代碼塊作用域??即可。
●鏈接屬性
一共有三種鏈接屬性:external??internal??none
None?:總是被當做單獨的個體,也就是說該標識符的多個聲明被當做獨立不同的實體。Internal?:在同一個源文件內部指的是同一個實體,在不同的源文件之中指的是不同的實體。external?:在所有的不同源文件中均指同一個實體。
具有文件作用域的標識符默認為external鏈接屬性,可以在這些標識符前面加上static關鍵字,使其鏈接屬性變更為internal;另外,對于一個函數,一般來說它也具有文件作用域。
其它作用域的標識符默認具有none標識符,在標識符加上extern關鍵字,使其鏈接屬性變更為external。
從技術上說,static?和?external?只有在聲明中才是必須的,然而,如果你在一個地方定義變量,并在使用這個變量的其他源文件的聲明中添加external?關鍵字,可以使讀者更容易理解你的意圖。????????????
??
?????
二: C語言 語句
●switch?語句經常搞錯,其標準格式為:
??????????cwitch?(x){
????????????case??x:?xxx?;?break;
???????????????.
???????????????.
???????????????????.
????????????????case??x:?xxx?;?break;
????????????????default?:?xxx?;?????????????
????????????????}
其中大括號千萬不要忘記。對于c語言中switch的工作機制,要有一定的了解。當程序執行到switch體內部時,程序會試圖尋找符合期望的?x?值,當找到之后,就會執行其后面的語句,并且對于該?case?之后的語句,會不加判斷一并執行!所以對于一般的switch語句,case?后面的相關執行命令之后要加break,跳出。
另外,附加對break的說明,一般break適用于跳出循環,比如while?循環和?for?循環,另外對于switch雖稱不上循環,但也可以跳出。所以一般情況下使用break也就只有這三個地方。
?●?printf格式大全
?printf的格式控制的完整格式:
%??-??0??m.n??l或h??格式字符
下面對組成格式說明的各項加以說明:
①%:表示格式說明的起始符號,不可缺少。
②-:有-表示左對齊輸出,如省略表示右對齊輸出。
③0:有0表示指定空位填0,如省略表示指定空位不填。
④m.n:m指域寬,即對應的輸出項在輸出設備上所占的字符數。N指精度。用于說明輸出的實型數的小數位數。為指定n時,隱含的精度為n=6位。
⑤l或h:l對整型指long型,對實型指double型。h用于將整型的格式字符修正為short型。
---------------------------------------
格式字符
格式字符用以指定輸出項的數據類型和輸出格式。
?①d格式:用來輸出十進制整數。有以下幾種用法:
%d:按整型數據的實際長度輸出。
%md:m為指定的輸出字段的寬度。如果數據的位數小于m,則左端補以空格,若大于m,則按實際位數輸出。
%ld:輸出長整型數據。
②o格式:以無符號八進制形式輸出整數。對長整型可以用"%lo"格式輸出。同樣也可以指定字段寬度用“%mo”格式輸出。
例:
???main()
???{?int?a?=?-1;
?????printf("%d,?%o",?a,?a);
???}
??運行結果:-1,177777
??程序解析:-1在內存單元中(以補碼形式存放)為(1111111111111111)2,轉換為八進制數為(177777)8。
③x格式:以無符號十六進制形式輸出整數。對長整型可以用"%lx"格式輸出。同樣也可以指定字段寬度用"%mx"格式輸出。
④u格式:以無符號十進制形式輸出整數。對長整型可以用"%lu"格式輸出。同樣也可以指定字段寬度用“%mu”格式輸出。
⑤c格式:輸出一個字符。
⑥s格式:用來輸出一個串。有幾中用法
%s:例如:printf("%s",?"CHINA")輸出"CHINA"字符串(不包括雙引號)。
%ms:輸出的字符串占m列,如字符串本身長度大于m,則突破獲m的限制,將字符串全部輸出。若串長小于m,則左補空格。
%-ms:如果串長小于m,則在m列范圍內,字符串向左靠,右補空格。
%m.ns:輸出占m列,但只取字符串中左端n個字符。這n個字符輸出在m列的右側,左補空格。
%-m.ns:其中m、n含義同上,n個字符輸出在m列范圍的左側,右補空格。如果n>m,則自動取n值,即保證n個字符正常輸出。
⑦f格式:用來輸出實數(包括單、雙精度),以小數形式輸出。有以下幾種用法:
%f:不指定寬度,整數部分全部輸出并輸出6位小數。
%m.nf:輸出共占m列,其中有n位小數,如數值寬度小于m左端補空格。?
%-m.nf:輸出共占n列,其中有n位小數,如數值寬度小于m右端補空格。
⑧e格式:以指數形式輸出實數。可用以下形式:
%e:數字部分(又稱尾數)輸出6位小數,指數部分占5位或4位。
%m.ne和%-m.ne:m、n和”-”字符含義與前相同。此處n指數據的數字部分的小數位數,m表示整個輸出數據所占的寬度。
⑨g格式:自動選f格式或e格式中較短的一種輸出,且不輸出無意義的零。
三、C語言 操作符
?●?C語言操作符優先級表:
| 優先級 | 運算符 | 名稱或含義 | 使用形式 | 結合方向 | 說明 |
| 1 | [] | 數組下標 | 數組名[常量表達式] | 左到右 | |
| () | 圓括號 | (表達式)/函數名(形參表) | |||
| . | 成員選擇(對象) | 對象.成員名 | |||
| -> | 成員選擇(指針) | 對象指針->成員名 | |||
| 2 | - | 負號運算符 | -表達式 | 右到左 | 單目運算符 |
| (類型) | 強制類型轉換 | (數據類型)表達式 | |||
| ++ | 自增運算符 | ++變量名/變量名++ | 單目運算符 | ||
| -- | 自減運算符 | --變量名/變量名-- | 單目運算符 | ||
| * | 取值運算符 | *指針變量 | 單目運算符 | ||
| & | 取地址運算符 | &變量名 | 單目運算符 | ||
| ! | 邏輯非運算符 | !表達式 | 單目運算符 | ||
| ~ | 按位取反運算符 | ~表達式 | 單目運算符 | ||
| sizeof | 長度運算符 | sizeof(表達式) | |||
| 3 | / | 除 | 表達式/表達式 | 左到右 | 雙目運算符 |
| * | 乘 | 表達式*表達式 | 雙目運算符 | ||
| % | 余數(取模) | 整型表達式/整型表達式 | 雙目運算符 | ||
| 4 | + | 加 | 表達式+表達式 | 左到右 | 雙目運算符 |
| - | 減 | 表達式-表達式 | 雙目運算符 | ||
| 5 | << | 左移 | 變量<<表達式 | 左到右 | 雙目運算符 |
| >> | 右移 | 變量>>表達式 | 雙目運算符 | ||
| 6 | > | 大于 | 表達式>表達式 | 左到右 | 雙目運算符 |
| >= | 大于等于 | 表達式>=表達式 | 雙目運算符 | ||
| < | 小于 | 表達式<表達式 | 雙目運算符 | ||
| <= | 小于等于 | 表達式<=表達式 | 雙目運算符 | ||
| 7 | == | 等于 | 表達式==表達式 | 左到右 | 雙目運算符 |
| != | 不等于 | 表達式!=?表達式 | 雙目運算符 | ||
| 8 | & | 按位與 | 表達式&表達式 | 左到右 | 雙目運算符 |
| 9 | ^ | 按位異或 | 表達式^表達式 | 左到右 | 雙目運算符 |
| 10 | | | 按位或 | 表達式|表達式 | 左到右 | 雙目運算符 |
| 11 | && | 邏輯與 | 表達式&&表達式 | 左到右 | 雙目運算符 |
| 12 | || | 邏輯或 | 表達式||表達式 | 左到右 | 雙目運算符 |
| 13 | ?: | 條件運算符 | 表達式1??表達式2:?表達式3 | 右到左 | 三目運算符 |
| 14 | = | 賦值運算符 | 變量=表達式 | 右到左 | |
| /= | 除后賦值 | 變量/=表達式 | |||
| *= | 乘后賦值 | 變量*=表達式 | |||
| %= | 取模后賦值 | 變量%=表達式 | |||
| += | 加后賦值 | 變量+=表達式 | |||
| -= | 減后賦值 | 變量-=表達式 | |||
| <<= | 左移后賦值 | 變量<<=表達式 | |||
| >>= | 右移后賦值 | 變量>>=表達式 | |||
| &= | 按位與后賦值 | 變量&=表達式 | |||
| ^= | 按位異或后賦值 | 變量^=表達式 | |||
| |= | 按位或后賦值 | 變量|=表達式 | |||
| 15 | , | 逗號運算符 | 表達式,表達式,… | 左到右 | 從左向右順序運算 |
?
●復雜表達式的求值順序有三個因素決定,首先是操作符的優先級,操作符的結合性以及操作符是否控制執行的順序。相鄰操作符的執行順序由它們的優先級決定,如果它們的優先級相同,那么由它們的操作符結合性決定。除此之外,編譯器可以自由決定使用任何順序進行求值,只要不違背??逗號??,?&&?,?||?,?:?所施加的順序即可。
●表達式的存在不一定會被求值。例如在sizeof(a=b+c)里面,表達式a=b+c是不會被求值的。另外由于??&&?,?||?,?:的短路效應,也有可能造成表達式不被求值。
●對于逗號表達式,其求值順序是從左到右,并且以最右邊那個表達式的值作為整個逗號表達式的值。而對于等號表達式,其除了能產生賦值這一行為外,其整個表達式也是有值的,它的值就是左值被賦予的值。
●對于移位操作符:存在兩種移位,邏輯移位和算術移位。邏輯左移和算術左移是一樣的。唯有有符號數的邏輯右移和算術右移才會不一樣。對于有符號數的算術右移,若最高位(符號位)為0,那么與邏輯右移是一樣的,若最高位是1,那么算術右移時,高位補1.編譯器對有符號數的右移是邏輯右移還是算術右移是取決于編譯器的。
●sizeof
??????假設對于一個結構?sruct?abc,那么sizeof(abc)是沒有意義的,正確的應該是
sizeof(struct?abc)
2.1.4??指針
?????●對所有的指針進行顯示的初始化是見好事情。
?????●對于?++*P?的計算順序要爛熟于心,由于++?和?*?的優先級相同,所以根據它們的結合性來進行判斷。因為結合性自右向左,所以先進行?*?操作?,再進行?++?操作。
?????●指針在和一個整數進行加或減操作時時鐘會根據合適的大小進行調整。
?????●指針可以進行的三種運算?:指針?+?整數??,?指針?-?指針?和?指針間的比較。對于后兩種,兩個指針必須指向同一個數組。兩個指針相減的結果是返回兩個指針間的單位長度,而兩個之爭間的比較也很容易理解。
?????●對于數組名基本上的時候都等同于指針,它和指針之間可以相互轉換,對于數組a[x]?和*(a+x)是等價的。對于指針?*?(p+x)?也可以用p[x]來表示。
五:C語言 函數
●函數定義
●函數聲明
??函數聲明的作用:當編譯器遇到一個函數調用時,它產生代碼傳遞參數并調用這個函數,而且接收這個函數的返回值(如果有的話)。但編譯器是怎么知道該函數期望接收的是什類型的參數和多少數量的參數呢?如何知道該函數的返回值(如果有的話)類型呢?這樣就是函數聲明的作用了。
??如果沒有函數聲明,編譯器會在調用這個函數時,假定所接受的參數是正確的,并同時假定一個整形的返回值。對于那些返回值并非整形的函數而言,這種隱式的認定常常導致錯誤。不過在VC++6.0上面貌似沒有聲明是不行的。
函數聲明的兩種方法,一是在使用前就有了該函數的定義,通常是在main函數之前。另一種是用函數原型來進行聲明。
●可變參數函數
??包含的頭文件是<stdarg.h>,需要用到三個宏:va_list?,?va_start?,?va_arg?,va_end?;其中va_list?是一種類型。
???一個求平均值的例子
???#include?<stdarg.h>
???float?average(num,...)
???{
??????int?count=0;
??????float?sum=0;
??????va_list??var_arg;
??????va_start(var_arg?,?num);
??????for(count=1;count<=num;count++)
???????sum?+=?va_arg(var_arg?,?int);
??????va_end(var_arg)
??????return?(sum?=?sum?/?count);
???}
六:C語言 數組
?????●對于數組?a[i]?那么a[i]?和?*(a+i)完全等價。
?????●對于數組?a[i]??.??*a++?絕對是非法的。?因為a雖然是一個指針,但是這是一個常量指針,其值是不可能改變的?。?*a++這一表達式做了兩件事,一是把拷貝出一份a值,用于*操作,這一步沒有錯,然而,另一步,這是a的自加1,這一步是不允許的。不過,當一個數組名作為一個函數的形參時,是可以對這個數組名實行?*a++操作的,原因在于作為形參,實際上市拷貝了一個數組名來使用而已,該數組名便具有了變量的性質。所以是可以這樣做的。這一結論可以從srcpy的實現中得到驗證。
????●c語言所有函數的參數都是一份拷貝而已,包括數組名和指針。那為什么傳數組或指針可以改變原來的值呢。這是因為得到了一份指針,那么根據指針的內容訪問內存,并修改相應的內存是我完全可以的。但要是想改變指針本身的內容,即指針所指向的位置是不可能的。
●?int??const?*p?:指向只讀整形變量的指針
???Int??*?const??p:指向整形的常量指針
●?int??*p[10]???;?根據優先級,先是數組,后是指針。所以它是指針數組
???????Int??(*p)[10]?;??先是指針,后是數組,所以是指向數組的的指針。和一個二維數組等價。
????●對于二維或者多為數組,把*轉化為?[?]?是一個明智之舉。?
???
七:字符串及字符串操作函數
●字符串長度測量函數:size_t??strlen(char??const??*string);注意到size_t?是無符號整形的,而一個無符號整形永遠是大于等于0的,所以如下判斷是錯誤的:
???????????if(strlen(x)-strlen(y)>=0)
?????????????……
正確的應該是:if((int)strlen(x)-(int)strlen(y)>=0)
????????????????????……
???●字符串拷貝函數:char?*strcpy(char?*dest?,?char?const*?src);?注意dest?和?src?不能重疊。
???●字符串拼接函數?:char?*strcat(char?*dest?,?char?const*?src);?注意dest?和?src?不能重疊。
???●詞典比較:?????????int?strcmp(char?const?*s1?,?char?const?*s2);?
????????????????????返回?0?:s1?=?s2;
????????????????????返回?正數?:?s1?>?s2;
????????????????????返回?負數?:?s1?<?s2;
帶有字符個數限制的字符串操作函數:
●字符串拷貝函數?:char?*strncpy(char?*dest?,?char?const*?src,size_t?lenth);?注意該函數不會保證NUL字符的拷貝。如下例子是比較穩妥的strncpy操作函數:
char??buffer[SIZE];
……
strncpy(buffer?,?name?,?SIZE);
buffer[SIZE-1]?=?'\n';
●字符串拼接函數?:char?*strcat(char?*dest?,?char?const*?src,?size_t?lenth);?
●詞典比較:?????????int?strcmp(char?const?*s1?,?char?const?*s2?,?size_t?lenth);?
●查找一個字符函數:?char?*strchr(char??const?*str?,?int?ch);返回第一個該字符的指針;另外一個與之相對應得函數時?char?*strrchr(char?const?*str?,?int?ch);返回最后一個匹配字符的指針。
●查找任何幾個字符。char?*strpbrk(char?const?*str?,?char?const?*group);
●查找一個子字符串:char?*strstr(char?const?*s1?,?char?const?*s2);
●查找第一個“是”/?“不是”位置??size_t?strspn(cahr?const?*str?,?cahr?const?*group);??size_t??strcspn(cahr?const?*str?,?cahr?const?*group);??注意返回值,第一個位置是0.
●分解字符串char?*(char?*s?,?char?*delim);使用方法如下:
?????????char?*p?=?strtok(s1?,?“;”);
?????????P?=?strtok(NULL?,?“;”);
總結
以上是生活随笔為你收集整理的嵌入式基础之----C语言的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 杠杆收购比例 什么是杠杆收购
- 下一篇: TCP/IP 中的二进制反码求和算法