看完這篇,輕松弄懂STM32 C語言變量的定義和初始化
我們今天探討C語言變量的定義和初始化。那么我們首先要明確三個(gè)問題。第一,我們要明白什么是變量,或者為什么C語言一定要有變量;第二個(gè)在C語言中如何去表達(dá)這些變量,或者說C語言都有什么類型的變量如何定義這些變量;第三,變量為什么要初始化,以及如何初始化。
第一個(gè)問題,關(guān)于變量,一個(gè)最通俗的理解就是變化的量。本來外在的物質(zhì)世界就是在不斷變化的,不是有句話么:“唯一不變的就是變化”。C語言作為描述客觀世界變化的一種語言,首先就是要有能夠?qū)ν饨缡挛镒兓癄顟B(tài)量化的工具,那么這個(gè)工具就是變量。數(shù)字世界,首先就是量化,這個(gè)是一切后續(xù)工作的基礎(chǔ)。
我們下面拿幾個(gè)常用的變量類型進(jìn)行說明,比如char型變量,它主要是用來應(yīng)對0?– 255之間變化的事物的,比如字符什么的。比如float,浮點(diǎn)型的變量,它主要是量化客觀世界中模擬量的事物,比如汽車的速度、太陽光的強(qiáng)度等等;再比如int型的變量,它的描述范圍就比char型大得多了,它主要是應(yīng)對整數(shù)變化的客觀事物的,比如學(xué)生的個(gè)數(shù)、蘋果的個(gè)數(shù)等等。
那么實(shí)際上,我們說C語言的變量遠(yuǎn)不止這些簡單的數(shù)據(jù)類型,是吧。我們還有數(shù)組,結(jié)構(gòu)體,還有指針、棧、鏈表等等。每種數(shù)據(jù)類型的出現(xiàn)都是為了解決一個(gè)量化的問題,比如指針,它主要是定位量化計(jì)算機(jī)中內(nèi)存尋址問題;比如結(jié)構(gòu)體,它的定位主要是用來描述復(fù)雜事物的,就比如汽車,它不僅有行駛的速度,還有輪子的個(gè)數(shù),椅子的個(gè)數(shù)等等;再比如棧,它的主要作用是解決任務(wù)切換以及函數(shù)調(diào)用時(shí),程序現(xiàn)場的保護(hù)問題。
那么也就是說每一個(gè)變量類型或者量化工具類型的出現(xiàn),都是有原因的,都是為了解決實(shí)際問題的。當(dāng)我們從這個(gè)視角去看這些變量類型和必要性的時(shí)候,我們的理解就會(huì)深刻很多。舉個(gè)例子,比如面向?qū)ο髷?shù)據(jù)類型的產(chǎn)生,就是把方法或者函數(shù)集成到了一個(gè)類型中,這樣就可以更為準(zhǔn)確的去描述客觀事物,比如一個(gè)狗狗,它不僅有一條大尾巴,還可以跑得非常快,大尾巴是數(shù)據(jù),會(huì)跑且跑得快是方法。面向?qū)ο蟮恼Z言比如C++或者Java,就把這些變量和方法封裝起來,形成一個(gè)新的更為綜合的量化工具,那就是對象。
站在C語言的基礎(chǔ)上,往上看是C++語言等面向?qū)ο蟮?,但是如果往下看,比如到了匯編級別,就是另外一番場景。我們知道匯編語言是最接近機(jī)器的語言,對于某一類型的單片機(jī),它一般有幾十條特定中匯編指令。但是我們說匯編語言是沒有數(shù)據(jù)類型的,它操作的只有二進(jìn)制類型的數(shù)據(jù),并沒有對這些數(shù)據(jù)進(jìn)行按照其屬性進(jìn)行分類。沒有根據(jù)屬性對數(shù)據(jù)進(jìn)行分類,其實(shí)也就是說沒有對量化工具進(jìn)行分類,那么人類的大腦就要耗費(fèi)更多的能量去理解匯編程序,人的大腦本身都是很懶的,能省能量肯定是想辦法節(jié)省能量。從這個(gè)角度上的看,匯編語言更像是機(jī)器語言。
但是我們說電腦本身就是機(jī)器,不同匯編語言的指令集才能真正反映各個(gè)芯片架構(gòu)的不同,指令集不同可能對應(yīng)的電路也是不同的。任何高級語言最后還是要在特定的機(jī)器上運(yùn)行的,那也就是說這些高級語言最后還是要翻譯成特定的匯編語言。這個(gè)翻譯的工作就是編譯器要做的事情。另外,軟件的開發(fā)還要有量好的代碼編輯環(huán)境以及調(diào)試環(huán)境(比如支持單步調(diào)試,實(shí)時(shí)查看寄存器及存儲(chǔ)單元的數(shù)據(jù)),所以一款新的單片機(jī)是不是好用會(huì)有多方面的因素影響的,也不能只看指令集的執(zhí)行效率。
第二個(gè)問題,C語言都有什么類型的變量呢?我們可以用一張表來大概描述一下,下面這張表對C語言的數(shù)據(jù)類型進(jìn)行了相對完整的總結(jié)。大家可以看一下,整體的數(shù)據(jù)類型被劃分為四類:基本類型,構(gòu)造類型(組合類型),指針類型還有空類型?;镜臄?shù)據(jù)類型肯定是根本,C語言在級別數(shù)據(jù)類型的基礎(chǔ)上構(gòu)造出更為復(fù)雜的數(shù)據(jù)類型,用于描述相對復(fù)雜的事物,比如結(jié)構(gòu)體等等。那么C語言就是使用這些相對抽象的基本類型,去量化和描述紛繁復(fù)雜的外部世界的。我們在前面已經(jīng)提到了絕大多數(shù)數(shù)據(jù)類型產(chǎn)生的原因,這里就不再贅述了。如果有還不理解的同學(xué),可以自己上網(wǎng)去查一查資料。
從下面這幅圖可以看出,不同的基礎(chǔ)數(shù)據(jù)類型器長度是不一樣的,而且同一種數(shù)據(jù)類型在不同的機(jī)器和編譯器編譯下其數(shù)據(jù)長度也是不一樣的。不同的基礎(chǔ)數(shù)據(jù)類型,所占據(jù)是二進(jìn)制數(shù)據(jù)位數(shù)發(fā)生不同,這個(gè)是可以理解的。對于相對簡單的事物,比如字符,本來就不需要使用那么長的位數(shù)來表達(dá),這個(gè)是基本訴求。再一個(gè),比如對于char類型這種需要較少位數(shù)就可以表達(dá)的可以量化的事物,如果使用int這種長度的數(shù)據(jù)去表達(dá),本身也是對計(jì)算機(jī)存儲(chǔ)資源的浪費(fèi)?;谏鲜鰞蓚€(gè)原因,才出現(xiàn)了不同的數(shù)據(jù)類型有不同的長度的現(xiàn)象。我們在實(shí)際編程的時(shí)候,從設(shè)計(jì)的角度上來看,肯定是選擇使用最少的存儲(chǔ)位數(shù)來量化自己要描述的事物,這樣占用的資源才能是最少。當(dāng)程序代碼行數(shù)非常多的時(shí)候,這種差異就會(huì)相對非常明顯了。
下面,我們來探討第三個(gè)問題,變量為什么要初始化以及如何初始化。我們首先解釋一下為什么單片機(jī)數(shù)據(jù)最好要初始化。眾所周知,變量是存儲(chǔ)在RAM中,掉電后即丟失,上電后默認(rèn)全為0。那么這樣的話沒賦初值的變量值全為0,這也應(yīng)該是大家認(rèn)為理所當(dāng)然的。但是實(shí)際上并不是這樣,有些類型的單片機(jī),當(dāng)單片機(jī)復(fù)位的時(shí)候(包括硬件復(fù)位即按下復(fù)位按鈕,看門狗復(fù)位,以及其它軟件程序復(fù)位),單片機(jī)只是重新跳回到main函數(shù)開始執(zhí)行,而并沒有清空RAM!所以,那些只是定義而沒有賦初值的變量(尤其是全局變量)依然會(huì)使用復(fù)位前留下來的值!那么這樣,程序運(yùn)行可能就會(huì)出現(xiàn)異常的結(jié)果,尤其是指針變量。數(shù)據(jù)有一個(gè)初始的值,整個(gè)程序也就有了一個(gè)初始狀態(tài),初始狀態(tài)確定了,如果程序設(shè)計(jì)得沒有問題,那么就可以按照既定的規(guī)則跑下去。如果程序錯(cuò)誤發(fā)生在初始位置上,那就太可惜了。大家在編程的時(shí)候,一定要注意這個(gè)現(xiàn)象。
那么下面我們看一下,如何對變量進(jìn)行初始化。不同的變量類型,初始化的方式肯定是不一樣的。首先對于基礎(chǔ)的數(shù)據(jù)類型,可以直接初始化成想要的值即可。那么對于數(shù)組、結(jié)構(gòu)體等類型,初始化的方法就具體問題具體分析,各具特色了。我們下面舉例子進(jìn)行說明。
一維數(shù)組:
int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int a[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int a[10] = {0};
int a[] = {1, 2, 3, 4, 5};
二維數(shù)組:
int a[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
int a[3][4] = {{1}, {5}, {9}};
/*
????1 0 0 0
????5 0 0 0
????9 0 0 0
*/
int a[3][4] = {{1}, {0, 6}, {0, 0, 11}};
/*
????1 0 0 0
????0 6 0 0
????0 0 11 0
*/
int a[3][4] = {{1}, {5, 6}};
/*
????1 0 0 0
????5 6 0 0
????0 0 0 0
*/
int a[][4] = {{0, 0, 3}, {}, {0, 10}};
/*
????0 0 3 0
????0 0 0 0
????0 10 0 0
*/
字符數(shù)組:
char c[10] = {'I', ' ', 'a', 'm', ' ', 'h', 'a', 'p', 'p', 'y'};
char c[2][3] = {{'y', 'o', 'u'}, {'a', 'r', 'e'}};
char c[] = {"I am happy"};
char c[] = "I am happy"; ???//?可以省略花括號(hào)
char c[] = {'I', ' ', 'a', 'm', ' ', 'h', 'a', 'p', 'p', 'y', ''}; //?與上面等價(jià)
char *p;
p = "I love China"; //?正確
char c[14];
c = "I love China"; //?錯(cuò)誤
c[14] = "I love China"; //?錯(cuò)誤
結(jié)構(gòu)體:
struct {
char name[20];
int age;
}student1, student2;
//匿名結(jié)構(gòu)體
struct Student {
char name[20];
int age;
}student1, student2;
//聲明結(jié)構(gòu)體
struct Student {
char name[20];
int age;
}student1 = {"xiaoming", 20};
struct Student student1={.age=12}; // C99可以只對age進(jìn)行初始化,其他變量初始化成零
聯(lián)合體:
union Data {
int i;
char ch;
float f;
}a = {1, 'a', 1.5}; //?錯(cuò)誤,不能同時(shí)初a.ch = 'A'; //?正確
對共用體賦值要指明賦值對象,如
a.f = 1.5; ?//?正確
a.i = 40; ??//?正確
a = 1; ?????//?錯(cuò)誤,沒有指明賦值對象始化3個(gè)
union Data a = {16}; //?正確
union Data a = {.ch='j'}; //?正確?C99新增
枚舉:
第一個(gè)枚舉成員的默認(rèn)值為整型的?0,后續(xù)枚舉成員的值在前一個(gè)成員上加 1。
聲明
enum Weekday {sun, mon, tue, wed, thu, fri, sat};
定義
enum Weekday workday, weedkend;
賦值
enum Weekday {sun=7, mon=1, tue, wed, thu, fri, sat};
// sun=7, mon=1, tue=2, wed=3, thu=4, fri=5, sat=6
把上述三個(gè)問題到搞清楚后,我們的這篇文章到此就結(jié)束了。
參考資料
(復(fù)制鏈接在瀏覽器打開)
①?C語言數(shù)據(jù)類型總結(jié)?
https://blog.csdn.net/xingjiarong/article/details/46942649
②?C++繼承?
https://www.runoob.com/cplusplus/cpp-inheritance.html
③單片機(jī)C語言探究--為什么變量最好要賦初值?
https://blog.csdn.net/weixin_34342207/article/details/92999746
④?C語言-定義與初始化總結(jié)?
https://blog.csdn.net/syzdev/article/details/103532435