C語(yǔ)言的設(shè)計(jì)哲學(xué)
C語(yǔ)言的設(shè)計(jì)哲學(xué)可以概括為"信任程序員"。
與許多現(xiàn)代編程語(yǔ)言不同,C語(yǔ)言幾乎不對(duì)程序員的行為設(shè)限,它假定程序員知道自己在做什么。
因此C語(yǔ)言實(shí)際上是一門對(duì)程序員要求很高的語(yǔ)言。
幾十年過(guò)去了,盡管出現(xiàn)了眾多新的編程語(yǔ)言,C語(yǔ)言仍然是操作系統(tǒng)和設(shè)備驅(qū)動(dòng)開(kāi)發(fā)的主導(dǎo)語(yǔ)言。這不是偶然,而是C語(yǔ)言特性與系統(tǒng)編程需求的完美契合,這其中的關(guān)鍵因素之一就是C語(yǔ)言能夠?qū)崿F(xiàn)對(duì)硬件的直接控制。
這是怎么實(shí)現(xiàn)的呢?
CPU寄存器與內(nèi)存
在理解C語(yǔ)言如何直接控制硬件之前,我們需要先了解計(jì)算機(jī)硬件的兩個(gè)核心組成部分:CPU寄存器和物理內(nèi)存。
這兩個(gè)組件構(gòu)成了計(jì)算機(jī)執(zhí)行指令和存儲(chǔ)數(shù)據(jù)的基礎(chǔ),也是C語(yǔ)言能夠?qū)崿F(xiàn)底層控制的關(guān)鍵接口。
CPU寄存器是處理器內(nèi)部的高速、極小容量的存儲(chǔ)單元,它們是CPU執(zhí)行指令時(shí)的直接操作對(duì)象。
可以將寄存器想象為CPU的"工作臺(tái)",所有的計(jì)算和數(shù)據(jù)處理都必須在這個(gè)"工作臺(tái)"上進(jìn)行。
無(wú)論是加載指令、執(zhí)行運(yùn)算、還是訪問(wèn)內(nèi)存,都離不開(kāi)寄存器的參與。
寄存器的主要作用包括:
存儲(chǔ)指令執(zhí)行過(guò)程中的臨時(shí)數(shù)據(jù)
保存內(nèi)存地址,用于內(nèi)存訪問(wèn)
記錄CPU的工作狀態(tài)(如運(yùn)算結(jié)果是否為零、是否產(chǎn)生進(jìn)位等)
控制程序執(zhí)行流程(如下一條指令的地址)
接著我們看物理內(nèi)存。
物理內(nèi)存,通常指主存儲(chǔ)器(RAM,隨機(jī)訪問(wèn)存儲(chǔ)器),是計(jì)算機(jī)用于存儲(chǔ)程序代碼、數(shù)據(jù)和運(yùn)行時(shí)信息的主要存儲(chǔ)設(shè)備。如果將寄存器比作CPU的"工作臺(tái)",那么物理內(nèi)存就是計(jì)算機(jī)的"大倉(cāng)庫(kù)",存儲(chǔ)著程序運(yùn)行所需的所有數(shù)據(jù)。
物理內(nèi)存的主要作用包括:
存儲(chǔ)正在執(zhí)行的程序代碼
保存程序運(yùn)行時(shí)的數(shù)據(jù)(如變量、數(shù)組、結(jié)構(gòu)體等)
維護(hù)程序的運(yùn)行狀態(tài)(如函數(shù)調(diào)用棧、堆內(nèi)存等)
而我們說(shuō)C語(yǔ)言可以直接控制硬件更多體現(xiàn)在對(duì)寄存器和內(nèi)存的控制上。
C語(yǔ)言控制寄存器的利器:內(nèi)聯(lián)匯編
內(nèi)聯(lián)匯編允許在C代碼中直接嵌入?yún)R編指令,實(shí)現(xiàn)C語(yǔ)法無(wú)法表達(dá)的極底層操作:
直接讀寫特定CPU寄存器:訪問(wèn)EAX、CR0等特定寄存器。
執(zhí)行特權(quán)指令:如修改頁(yè)表、更改處理器模式等需要特殊權(quán)限的操作。
優(yōu)化極致性能:在性能關(guān)鍵路徑上使用手工優(yōu)化的匯編代碼等
GCC編譯器提供了強(qiáng)大的內(nèi)聯(lián)匯編支持,基本語(yǔ)法如下:
// 將EAX寄存器的值存入result變量 asm volatile ("movl %%eax, %0" : "=r"(result) : ); // 將value變量的值加載到EAX寄存器 asm volatile ("movl %1, %%eax" : : "r"(value)); // 進(jìn)行系統(tǒng)調(diào)用 asm volatile ("int $0x80" : : "a"(syscall_num), "b"(arg1));
內(nèi)聯(lián)匯編是C語(yǔ)言穿透自身抽象、直達(dá)硬件的最直接體現(xiàn)。
asm
塊中的指令可以直接操作物理寄存器(EAX, EBX等) 或特定內(nèi)存地址,繞過(guò)C語(yǔ)言的變量抽象和編譯器的寄存器分配機(jī)制。
操作系統(tǒng)內(nèi)核大量使用內(nèi)聯(lián)匯編來(lái)實(shí)現(xiàn):
上下文切換(保存和恢復(fù)寄存器狀態(tài))
處理器特權(quán)級(jí)別切換
頁(yè)表操作
中斷處理
原子操作
內(nèi)聯(lián)匯編雖然強(qiáng)大,但也帶來(lái)了風(fēng)險(xiǎn)和挑戰(zhàn):
破壞可移植性
增加代碼復(fù)雜度
可能引入難以調(diào)試的錯(cuò)誤
因此,內(nèi)聯(lián)匯編通常被視為"最后的手段",僅在絕對(duì)必要時(shí)使用,并且通常會(huì)被封裝在宏或函數(shù)中以提高可維護(hù)性。
C語(yǔ)言控制內(nèi)存的利器:指針
在了解C語(yǔ)言中的指針之前我們必須明白變量的本質(zhì)。
當(dāng)我們?cè)贑語(yǔ)言中聲明一個(gè)變量(如int a; char c;
)時(shí),我們實(shí)際上是在做什么?
從本質(zhì)上講,我們是在向編譯器申請(qǐng)一塊內(nèi)存區(qū)域,并賦予它一個(gè)名字和類型。編譯器會(huì)根據(jù)變量的類型分配適當(dāng)大小的內(nèi)存空間,并記錄這塊內(nèi)存的起始地址。
例如,當(dāng)我們聲明int a;
時(shí),編譯器會(huì):
在適當(dāng)?shù)膬?nèi)存區(qū)域(通常是棧)分配4個(gè)字節(jié)(在大多數(shù)現(xiàn)代系統(tǒng)上)的空間
將這塊內(nèi)存與標(biāo)識(shí)符
a
關(guān)聯(lián)起來(lái)記錄這塊內(nèi)存應(yīng)該被解釋為整數(shù)類型
變量名是程序員友好的標(biāo)識(shí)符,它只存在于源代碼和編譯階段。一旦程序被編譯成機(jī)器碼,變量名就會(huì)被替換為具體的內(nèi)存地址。當(dāng)CPU執(zhí)行指令時(shí),它不知道變量名的存在,它只知道要操作特定內(nèi)存地址上的數(shù)據(jù)。
從本質(zhì)上講,指針也是一個(gè)變量,只不過(guò)其值是另一個(gè)變量的內(nèi)存地址,換句話說(shuō),指針"指向"內(nèi)存中的某個(gè)位置。
例如,int *p;
聲明了一個(gè)指向整數(shù)的指針,這告訴編譯器,p
的值是一個(gè)內(nèi)存地址,而這個(gè)地址上存儲(chǔ)的數(shù)據(jù)應(yīng)該被解釋為整數(shù)。
既然指針也是一個(gè)變量,那么就可以向普通變量一樣進(jìn)行常規(guī)的加減等操作,因此利用指針C語(yǔ)言能夠直接操作內(nèi)存地址,實(shí)現(xiàn)對(duì)硬件的精確控制。
這里必須注意到在用戶態(tài)盡管可以使用指針,但指針操作的是虛擬內(nèi)存,依然不是真正的物理內(nèi)存,但在內(nèi)核態(tài)就不一樣了,操作系統(tǒng)可以真正的直接操作物理內(nèi)存。
正是通過(guò)指針,C語(yǔ)言建立了高級(jí)語(yǔ)言抽象與底層硬件操作之間的橋梁。
C語(yǔ)言的底層控制能力使其成為應(yīng)對(duì)這些挑戰(zhàn)的理想工具,盡管這也意味著程序員需要承擔(dān)更多責(zé)任,確保代碼的正確性和安全性。
總之一句話就是當(dāng)你使用C語(yǔ)言進(jìn)行系統(tǒng)編程時(shí),你需要清楚的知道你在干啥
來(lái)源:碼農(nóng)的荒島求生
編輯:月
轉(zhuǎn)載內(nèi)容僅代表作者觀點(diǎn)
不代表中科院物理所立場(chǎng)
如需轉(zhuǎn)載請(qǐng)聯(lián)系原公眾號(hào)
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺(tái)“網(wǎng)易號(hào)”用戶上傳并發(fā)布,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.