對于工科生,,C語言是一門必修課。 標(biāo)準(zhǔn)C(ANSI C) 這個 看似簡單 的語言在硬件底層編程,、嵌入式開發(fā)領(lǐng)域還是穩(wěn)坐頭把交椅,。在20年5月份,C語言就憑借其在醫(yī)療設(shè)備上的廣泛應(yīng)用,,時隔五年重回編程語言榜首,。
同學(xué)們在拿到學(xué)分之后還有沒有使用這門“手藝”呢,? 想做軟硬件項目的同學(xué)還需要補足哪些知識呢,? 不論是正在學(xué)習(xí)還是曾經(jīng)學(xué)習(xí)過C語言的同學(xué),這篇文章總結(jié)的一些要點能提供一個 新的角度來理解C語言的設(shè)計理念和特性 ,。 一起來看看吧,! 原文鏈接: cnblogs/huxiaoan/p/14749360.html?utm_source=tuicool&utm_medium=referral
一共有多少個關(guān)鍵字?這個的確不好說,,在C99和C11里都添加了新的關(guān)鍵字,,也有的關(guān)鍵字由于過時淡出了我們的視線。下面這些關(guān)鍵字的用法都掌握了嗎,? auto 它可謂默默無聞,,不少人應(yīng)該知道它沒什么用——局部變量默認(rèn)就是auto類型。除此之外,,auto變量存放在動態(tài)儲存區(qū)中的棧區(qū),。也就是這種變量時有時無,壽命可變,,自動(auto)管理,。 注意:正因為來去自如,創(chuàng)建的局部變量不會自動初始化為零??!切記 但是,在C++11里auto翻身了,,可以用作 類型推導(dǎo) ,。比如:
可是這和C有什么關(guān)系,? static 你能想到static的幾個用法,?有人說是三個,我覺得就兩個,。 修飾全局變量或函數(shù)時,,它的作用是 僅限本文件訪問 。C語言里沒有命名空間,,如果不加static,,不同文件里的同名變量會引起混淆,畢竟他們的作用域相同,。 修飾局部變量,,成為存放在靜態(tài)儲存區(qū)的靜態(tài)變量。生命周期為整個程序執(zhí)行過程,。與auto不同,,靜態(tài)變量在程序開始之前就初始化完畢。這也就是常說的第三個用法,,將局部變量初始化為零,。其實這只是變量存放在靜態(tài)儲存區(qū)的一個特征,所以不單獨拿出來。 volatile 大多數(shù)學(xué)校課程是不會用到它的,,接觸單片機和多線程就能懂得它的重要性,。 volatile的意思是”易變的、無常的“,,名副其實。 volatile是對變量的修飾,,比如 volatile int flag=0; 它是對編譯器的提醒: ”嘿,,這變量是變化無常的,你可小心點,!“ 這針對的是編譯器的”小聰明“——優(yōu)化,。 舉個例子
計算機運算要先把變量從內(nèi)存加載到寄存器,,這一步是耗時間的,。編譯器一看,前腳我才讓flag=1,,這個flag還在寄存器里,,到下一句判斷之間也沒有能改變flag的語句,那我不直接用這個寄存器里的flag=1嘛,。 可萬萬沒想到,,就在flag=1之后,if之前,,來了一次 硬件中斷 ,,終端回調(diào)函數(shù)把flag改成0了。 編譯器是料不到的,,就認(rèn)為flag=1,。這在很多實際情況下是很恐怖的。 不僅僅是中斷,,插入一段匯編,,其他線程改變內(nèi)存都會引起這類問題。 如果改為 volatile int flag=0; ,凡是用到這個變量,, 就會去內(nèi)存里不怕麻煩地找到它 ,,不再偷懶。 當(dāng)時我年輕不懂事,,一個單片機項目里用中斷改變標(biāo)志位,。怎么都不正常,后來哥們讓我在標(biāo)志前面加個volatile就解決了,。,。。 __WEAK 這 不是個關(guān)鍵字 ,這只是GCC的一個特性,??碨TM32官方固件庫的同學(xué)應(yīng)該沒少見到它,但它不是C++里virtual那種虛函數(shù),。 如果有同名的不帶_WEAK前綴的函數(shù),,優(yōu)先使用不帶的。 如果用戶自定義了,,那就使用用戶的,,如果沒有,那就用默認(rèn)的,。這樣方便用戶自定義一些回調(diào)函數(shù),、處理函數(shù)。 相信大家對C語言的 強類型 特性印象非常深刻,。尤其是printf的格式化輸出和復(fù)雜指針的類型,。 程序不就是數(shù)據(jù)結(jié)構(gòu)+算法,基本類型則是構(gòu)成數(shù)據(jù)結(jié)構(gòu)高樓大廈的一磚一瓦,。 char 冥冥之中,,我覺得char類型是最神奇的類型。在C語言標(biāo)準(zhǔn)里char的大小是1 Byte,,這是不會變的,,也就是sizeof(char)無論在哪都是1。但是:
輸出是多少,?是4,一個int的大??!沒錯, 字符常量的類型不是char而是int ,。 來放松一下,。 你平時怎么讀“char”?反正我是讀了好幾年的 ”差“ ,,后來轉(zhuǎn)念一想,,字符的英文是character[?k?r?kt?(r)],那不應(yīng)該是。,。,。。其實有三個發(fā)音,,英文char(煤炭),、car(汽車),、care(關(guān)心)都可以。 float 浮點數(shù)比整形更貼近實際,,也不至于出現(xiàn)除法去尾的情況,。要注意的是,計算機的浮點數(shù)是分立的,,有時候1.30會變成1.299999,。比如matlab里查看eps(epsilon)可以得到浮點數(shù)的最小分度值。(win64下)
三者的關(guān)系可以說是糾纏不清,。 剛學(xué)C都遇到過,函數(shù)返回值可以是一個龐大的結(jié)構(gòu)體,,卻不能是一個簡單的古玩論壇數(shù)組??墒?,數(shù)組類型可以是結(jié)構(gòu)體,結(jié)構(gòu)體的成員也可以包含數(shù)組,,僅僅是組織方式的區(qū)別,。 結(jié)構(gòu)體和數(shù)組 舉例說明一下,現(xiàn)有結(jié)構(gòu)體struct_a,,有成員a,、b、c三個,。
注意最后一種寫法,有時候編譯器為了對齊,,會填充一些地址,,導(dǎo)致不連續(xù)。不要這樣訪問結(jié)構(gòu)體成員,! 如果是數(shù)組呢,?我們常用arr[n]這種方式來訪問數(shù)組成員,”[]“這個符號的用途是把a[b]變成*(a+b),。請結(jié)合例子理解一下,。
數(shù)組和指針 把數(shù)組傳入函數(shù)時,,有兩種寫法
在C里,第一種會自動轉(zhuǎn)化成第二種,,所以訪問數(shù)組本質(zhì)還是指針,。 教你個竅門: int arr[10]; int* ptr=&arr[-1]; 然后就可以從下標(biāo)1開始用數(shù)組ptr[]。
毫無疑問,,指針是個麻煩事,。比如 char *(*(*(a[2])())() 是一個 包含2個指向返回 指向字符的指針的函數(shù)指針的數(shù)組 ,幾乎很難看出它到底是數(shù)組還是指針,。 希望這些要點能幫到你,! 優(yōu)先與[]結(jié)合再與*結(jié)合 指針類型:把聲明中指針名稱去掉,就得到了指針的類型,。 Int * ptr→int * Int(* ptr)[3]→int(*)[3] 同時注意結(jié)合關(guān)系,,比如下面這個的名稱就是ptr[3],而不是上面的ptr int *ptr[3]->int * 所指向的類型:去掉指針名稱和一個* int*ptr; : 指針?biāo)赶虻念愋褪?int int ** ptr; : 指針?biāo)赶虻牡念愋褪?int* int(*ptr)[3]; : 指針?biāo)赶虻牡念愋褪?int()[3] 指針賦值時,,左邊指針?biāo)赶虻念愋捅仨毦哂杏疫呏羔標(biāo)赶蝾愋偷娜肯薅ǚ?,比?/p>
C語言絕不是Python那樣自備電池的全能型語言,,它是一門中級語言,。 標(biāo)準(zhǔn)庫函數(shù)往往看起來簡陋而且有缺陷。 來了解一下吧,。
這三個函數(shù)的執(zhí)行順序是不確定的,C標(biāo)準(zhǔn)把選擇順序的權(quán)力交給編譯器以便針對各個平臺進行優(yōu)化,。 可以確定的一點是,,乘法優(yōu)先級高于加法。 可能很多人都知道這個考點,,函數(shù)參數(shù)壓棧的順序是從右至左,,右邊的表達式會先被運行。 重點在后面的問號 C標(biāo)準(zhǔn)對于壓棧順序 并沒有明確規(guī)定 ,,也就是編譯器 可以修改成從左至右 的壓棧順序,。 默認(rèn)的從右至左是為了支持可變參數(shù),用來計算棧的大小,。 早期的 gets() 導(dǎo)致了蠕蟲病毒,,因為它不檢查緩沖區(qū)是否越界,其實scanf也有這個問題,。標(biāo)準(zhǔn)輸入輸出有許多設(shè)計上的細(xì)節(jié)需要被了解,,比如printf使用%來轉(zhuǎn)義%而不是\ , scanf里的 并不代表等待一個換行符而是讀取并拋棄所有空格...... 這些設(shè)計上的特點可能會在意想不到的地方產(chǎn)生出意想不到的效果。所以,,為了程序的健壯性,,多多了解它們吧。 預(yù)處理是個很好的想法,,增強了程序的可移植性和裁剪性,。 不僅僅是常見的#include,、#define,它的功能可以非常強大,,如果用得好的話,。 #include能做些什么? 復(fù)制,,原封不動地復(fù)制,。 甚至可以這樣:
真就是原封不動,,但要注意預(yù)處理命令是要 在一行的開頭,,獨占一行 。 如果是 #include<> 則會首先在標(biāo)準(zhǔn)位置(C語言安裝位置)搜尋,, #include "" 則現(xiàn)在同一文件夾下搜索,,找不到再去標(biāo)準(zhǔn)位置搜索。 在C++里,,用#define來定義常量是不被推薦的,,因為#define也僅僅是預(yù)處理替換,沒有類型檢查,。 推薦使用const修飾的變量。仁者見仁,,兩種方法各有特點,。
“ 看似簡單 ”這個描述對于C語言是再恰當(dāng)不過的,。最早的K&R標(biāo)準(zhǔn)只有40頁,,ANSI C手冊則超過了兩百頁,盡管這樣,,C語言特性給了編程者極大的自由,,衍生出來許多意想不到的用法和Bug。,。,。 本文整理的內(nèi)容不過是冰山一角,還有更多的進階內(nèi)容等待探索,。 周雖舊邦,,其命唯新。多次的標(biāo)準(zhǔn)更新已經(jīng)讓C語言不再是教科書里的簡陋模樣,。了解新特征,,有利于C語言的實際應(yīng)用。 希望大家都能夠熟練掌握這門 傳統(tǒng)藝能 ,! |
|
來自: 新用戶0175WbuX > 《待分類》