目錄【專欄一】嵌入式校招指南作者機(jī)械碩士,從零開始自學(xué)嵌入式軟件,21屆秋招進(jìn)入國內(nèi)芯片大廠。 從自身轉(zhuǎn)行經(jīng)歷來看,網(wǎng)上嵌入式學(xué)習(xí)路線的資料少之又少,大多千篇一律且復(fù)制粘貼。 而嵌入式入行門檻高,技能樹要求多,學(xué)習(xí)難度非常大,沒有有效的方法指導(dǎo),很容易迷失方向,錯(cuò)過校招。 在此專欄分享我的校招從零開始轉(zhuǎn)行經(jīng)驗(yàn),聽我給你娓娓道來~專欄鏈接 http://www.fangfengwang8.cn/creation/manager/columnDetail/MWZkkj1.專欄大綱&寫在前面2.轉(zhuǎn)行概述3.前期準(zhǔn)備4.自學(xué)教材推薦_基礎(chǔ)知識5.自學(xué)教材推薦_筆試準(zhǔn)備6.開發(fā)板&項(xiàng)目7.簡歷8.行業(yè)&公司9.城市&崗位10.消費(fèi)&工業(yè)電子類公司未完待續(xù)……【專欄二】嵌入式校招_面試經(jīng)驗(yàn)大全嵌入式軟件校招的常見問題,應(yīng)付校招面試的速效救心丸,你值得擁有! 嵌入式的知識太多太雜,不知道面試經(jīng)常問哪些? 書上說的知識點(diǎn)太抽象,沒有一定的基礎(chǔ)很難理解? 別怕,本專欄用通俗的語言和比喻,為你講清楚! 包含C語言、計(jì)算機(jī)組成原理、操作系統(tǒng)、數(shù)據(jù)結(jié)構(gòu)與算法及計(jì)算機(jī)網(wǎng)絡(luò)等,詳見大綱。1.【C語言】【1_變量】http://www.fangfengwang8.cn/discuss/4917738635256791042.【C語言】【2_關(guān)鍵字】http://www.fangfengwang8.cn/discuss/4975623096282767363.【C語言】【3_位運(yùn)算】http://www.fangfengwang8.cn/discuss/505894349847224320————————————————————【問】介紹一下enum的用法【答】enum是一種枚舉數(shù)據(jù)類型,描述的是一組常數(shù)的集合【解析】背景知識我們經(jīng)常會(huì)在代碼中使用各種各樣的數(shù)字來參與計(jì)算/賦值,那么如何更好地統(tǒng)一使用這些數(shù)字呢?假設(shè)小明同學(xué)參加秋招,某大廠發(fā)offer時(shí)給出的基本工資是根據(jù)個(gè)人情況而不同的,但是年終獎(jiǎng)都是按照較差、普通、優(yōu)秀、杰出來給予0、2、4、6個(gè)月來的。此時(shí)小明想要計(jì)算自己能夠拿到年包的各種可能性,應(yīng)該怎么辦呢?如果按照以下的方法計(jì)算,也不是不行,但是總感覺哪里怪怪的。。我們會(huì)發(fā)現(xiàn)1.case后面表示績效等級的數(shù)字,無法直觀地體現(xiàn)它代表的含義2.年終獎(jiǎng)的數(shù)額(多少個(gè)月),無法表示所代表的績效等級那么,怎么樣才能更直觀地表示出這些呢?對的!就是枚舉~我們將績效等級和其所對應(yīng)的年終獎(jiǎng)數(shù)額都用枚舉來表示,這樣就非常直觀明了~#include <stdio.h>#include <stdint.h>enum{ WORSE = 0, NORMAL, GOOD, OUTSTANDING}Bonus_Level;enum{ WORSE_BONUS = 0, NORMAL_BONUS = 1, GOOD_BONUS = 3, OUTSTANDING_BONUS = 5}Bonus;/* 小羽的嵌入式校招指南 */uint32_t CalSalary(uint32_t SalaryBase, uint8_t PerformLevel){ uint32_t AnnualSalary = 0; switch (PerformLevel) { case WORSE: AnnualSalary = SalaryBase * (12 + WORSE_BONUS); printf("\nYour SalaryBase is:[%dk], the AnnualSalary with WORSE is:[%dk]!\n" , SalaryBase, AnnualSalary); break; case NORMAL: AnnualSalary = SalaryBase * (12 + NORMAL_BONUS); printf("\nYour SalaryBase is:[%dk], the AnnualSalary with NORMAL is:[%dk]!\n" , SalaryBase, AnnualSalary); break; case GOOD: AnnualSalary = SalaryBase * (12 + GOOD_BONUS); printf("\nYour SalaryBase is:[%dk], the AnnualSalary with GOOD is:[%dk]!\n" , SalaryBase, AnnualSalary); break; case OUTSTANDING: AnnualSalary = SalaryBase * (12 + OUTSTANDING_BONUS); printf("\nYour SalaryBase is:[%dk], the AnnualSalary with OUTSTANDING is:[%dk]!\n\n" , SalaryBase, AnnualSalary); break; default: printf("Error Perform Level!\n"); break; } return AnnualSalary;}int main(void){ uint32_t BaseSalary; //k uint32_t AnnualSalary; printf("\nPlease input your BaseSalary:"); scanf("%d",&BaseSalary); //WORSE CalSalary(BaseSalary, WORSE); //NORMAL CalSalary(BaseSalary, NORMAL); //GOOD CalSalary(BaseSalary, GOOD); //OUTSTANDING CalSalary(BaseSalary, OUTSTANDING); return 0;}總結(jié)根據(jù)C語言編程規(guī)范可知,代碼的可讀性是優(yōu)先級極高的屬性。因?yàn)榇a首先是要服務(wù)于人,能夠讓人讀懂,其次才是它的性能。因此在處理這類純數(shù)字的情況時(shí),使用枚舉類型來代替純數(shù)字,能夠大大提高代碼可讀性~【問】位或操作【答】兩個(gè)數(shù)據(jù),按位進(jìn)行“或|”運(yùn)算。運(yùn)算規(guī)則:參加運(yùn)算的兩個(gè)對象只要有一個(gè)為1,其值為1。0與0位或等于0。 即 :0|0=0; 0|1=1; 1|0=1; 1|1=1;負(fù)數(shù)按補(bǔ)碼形式參加按位或運(yùn)算?!窘馕觥课徊僮鞯慕^大部分場景下,數(shù)據(jù)都是無符號的。即unsigned。此處僅考慮無符號場景。背景知識在某些場景下(尤其是驅(qū)動(dòng)崗位的寄存器中),我們僅需要表示某個(gè)狀態(tài)的開或關(guān),用0或者1表示即可。也就是說,僅需1bit即可。然而我們知道,就算是變量類型bool,也是需要占據(jù)1Byte空間(即使它只能用來表示0和1)。那么在某些需要大量表示狀態(tài)位的場景下(比如表示8盞燈的開關(guān)狀態(tài)),每個(gè)狀態(tài)位都使用1Byte來表示,那么需要8Byte。這對于資源極度緊張的嵌入式設(shè)備來說,會(huì)造成嚴(yán)重的資源浪費(fèi)!所以,聰明的先行者們就想到了使用變量中的每個(gè)bit來表示一個(gè)狀態(tài)開關(guān)。比如uint8_t Status = 21;那么6即是0001 0101。如果現(xiàn)在需要表示8盞燈的狀態(tài),那么21就表示第1(bit0)、第3(bit2)和第5(bit4)盞燈是亮著的。那么此時(shí),僅用一個(gè)Byte,就可以表示8盞燈的狀態(tài),真的是方便呀~移位左移:將變量向左移位操作,高位溢出丟棄,低位補(bǔ)0。int main(void){ uint8_t BulbStatus = 21; printf("\nThe original num:"); PrintToBin(8, &BulbStatus);/* 小羽的嵌入式校招指南 */ //左移2位 BulbStatus = BulbStatus << 2; printf("After Move 2 bits to the left:"); PrintToBin(8, &BulbStatus); //左移5位 BulbStatus = 21; BulbStatus = BulbStatus << 5; printf("After Move 5 bits to the left:"); PrintToBin(8, &BulbStatus); return 0;}21的二進(jìn)制是0001 0101。左移2位后等于84,二進(jìn)制為0101 0100。左移5位后為160,二進(jìn)制為1010 0000.大家發(fā)現(xiàn)一個(gè)現(xiàn)象沒有?2^2=4,21*4=84。2^5=32,21*32=672(超出char類型的[-127,128]),最終只留下672-(128*4)=160.(具體原理查看前面變量的文章——【問】*char型變量最大能表示的值?如果超出最大值怎么處理?http://www.fangfengwang8.cn/discuss/491773863525679104)我們可以發(fā)現(xiàn),對一個(gè)數(shù)左移1位就是乘以2,左移n位就是乘以2^n。在CPU中運(yùn)行位移運(yùn)算比乘除法快得多,所以這也是優(yōu)化程序運(yùn)行速度的一個(gè)技巧哦~右移:將變量向右移位操作,低位溢出丟棄,高位補(bǔ)0。21的二進(jìn)制是0001 0101。右移2位后等于5,二進(jìn)制為0000 0101。右移4位后為1,二進(jìn)制為0000 0001.2^2=4,21/4后取整等于5。2^4=16,21/16后取整等于1。所以,對一個(gè)數(shù)右移1位就是除以2后取整,左移n位就是除以2^n后取整~對數(shù)據(jù)的指定位設(shè)置為1因?yàn)槲换蜻\(yùn)算的特性,0與任何數(shù)與的結(jié)果都是該數(shù)本身。因此我們只需將我們想要設(shè)置的位跟1做與運(yùn)算,即可將該位設(shè)置為1.現(xiàn)在有個(gè)uchar型變量,用來表示8盞燈的開關(guān)狀態(tài)。如果現(xiàn)在燈全是暗著的,即0B0000 0000,我想要表示第2(bit1)和第3(bit2)盞燈為打開狀態(tài),應(yīng)該怎么做呢?int main(void){ uint8_t BulbStatus = 0;/* 小羽的嵌入式校招指南 */ //設(shè)置第2(bit1)盞燈狀態(tài)為打開 BulbStatus |= 1 << 1; //設(shè)置第3(bit2)盞燈狀態(tài)為打開 BulbStatus |= 1 << 2; printf("\nAfter Open The 2nd&3rd Bulb:"); PrintToBin(8, &BulbStatus); return 0;}我們通過位或操作,就達(dá)到了給指定bit置1的目的。當(dāng)然我們可以不需要每次只給一盞燈賦予狀態(tài),我們能不能一次性給兩盞燈的狀態(tài)都打開呢?答案是當(dāng)然可以~我們可以將我們想要打開的燈的位置信息,先用位或計(jì)算出來,然后再位或操作寫入BulbStatus。羽你俗說位或操作就是能夠精準(zhǔn)地將我們想要的一個(gè)或多個(gè)位置1,屏蔽掉無關(guān)位。舉個(gè)栗子,如果我想要在我的羽毛球線上,DIY一個(gè)特別點(diǎn)的logo,最好的方法是什么呢?手動(dòng)一點(diǎn)點(diǎn)地去畫不太現(xiàn)實(shí),因?yàn)槟莻€(gè)對畫畫技術(shù)要求太高,很容易走形。那么最好的方法是什么呢?用一塊板子蒙住,只留下我們希望畫的圖案的部分。見下圖:用記號筆,對著中間的空白地方直接畫,最后就會(huì)在羽毛球線上面留下一個(gè)可愛的只因(手動(dòng)滑稽)~只有我們選中的(中間空白處)部分才會(huì)被涂畫,其余部分不受影響,這就是位或操作與現(xiàn)實(shí)生活的聯(lián)系~————————————————【問】位與操作【答】兩個(gè)數(shù)據(jù),按位進(jìn)行“與&”運(yùn)算。運(yùn)算規(guī)則:兩個(gè)位的數(shù)據(jù)同時(shí)為“1”,結(jié)果才為“1”,否則為0。即:0&0=0; 0&1=0; 1&0=0; 1&1=1;負(fù)數(shù)按補(bǔ)碼形式參加按位與運(yùn)算?!窘馕觥砍R姂?yīng)用(1)判斷奇偶性a & 1 = 1;則a為奇數(shù)b & 1 = 0;則a為偶數(shù)這個(gè)很好理解,用位與運(yùn)算來判斷bit0的數(shù)值。從bit1開始往后,都是代表了2^N。只有bit0需要判斷奇偶性。(2) 對數(shù)據(jù)的指定位設(shè)置為0因?yàn)槲慌c運(yùn)算的特性,0與任何數(shù)與的結(jié)果都是0。因此我們只需將我們想要設(shè)置的位跟0做與運(yùn)算,即可將該位設(shè)置為0。還是以上面的uchar型變量表示8盞燈的開關(guān)狀態(tài)為例。第2(bit1)、第3(bit2)盞燈為打開,現(xiàn)在將第3(bit2)盞燈關(guān)閉。具體如下:將1左移2位,其值為0B0000 0100。再對其取反,得到0B1111 1011。此時(shí)我們就得到了bit2為0,其余bit為1的數(shù)(1和任何數(shù)做與&操作,結(jié)果是該值本身,所以我們只改變了值為0的那一位的數(shù)值)。關(guān)閉bit2后,就只剩下bit1的燈為打開狀態(tài)啦~(3)取指定位的數(shù)值 可以獲取某個(gè)數(shù)指定1個(gè)或多個(gè)位的數(shù)值。還是以前面的例子,假設(shè)現(xiàn)在第2(bit1)、第3(bit2)、第6(bit5)盞燈狀態(tài)為打開,即BulbStatus=38,0B0010 0110。如果想要獲取到底那幾盞燈是打開的,應(yīng)該怎么做呢?int main(void){ uint8_t BulbStatus = 0; uint8_t GetStatus = 0; int i;/* 小羽的嵌入式校招指南 */ //設(shè)置第2(bit1)、第3(bit2)盞燈狀態(tài)為打開 BulbStatus |= (1 << 1) | (1 << 2); printf("\nAfter Open The 2nd&3rd Bulb:"); PrintToBin(8, &BulbStatus); //依次獲取每盞燈的開關(guān)狀態(tài) for (i = 0; i < 8; i++) { if (0 != (BulbStatus & (1 << i)) ) { printf("The No.%d status is On\n\n",i + 1); } } return 0;}上面依次獲取0-7位的數(shù)值,從而判斷燈的開關(guān)狀態(tài)。這就是位與的用法~在驅(qū)動(dòng)崗位中,經(jīng)常會(huì)使用這種方法來獲取寄存器的值~當(dāng)然,也會(huì)用到位或來設(shè)置寄存器的值~羽你俗說①指定位置0同上述位或操作,只擦除指定位置的涂畫②獲取指定位的數(shù)值大家都用過答題卡吧?如下圖這種:在沒有讀卡器的時(shí)候,老師們是怎么快速批改試卷的呢?答案是:把正確答案全部鑿洞,然后直接放在學(xué)生的答題卡上面,看看洞內(nèi)是否有涂,就可以快速批改試卷啦~咱們的位與操作也是如此,提前選定指定位,查看這些位的數(shù)值~【問】異或操作【答】兩個(gè)數(shù)據(jù),按位進(jìn)行“異或^”運(yùn)算。運(yùn)算規(guī)則:兩個(gè)位的數(shù)據(jù)相同(異)時(shí)為“0”,不同時(shí)為“1”。即:0^0=0; 0^1=1; 1^0=1; 1^1=0;【解析】與0異或,保留原值;與1異或,翻轉(zhuǎn)數(shù)值還以前面的燈為例,如果我想做出跑馬燈的效果。第一步,將第1、3、5、7盞燈翻轉(zhuǎn);第二步,循環(huán)將每一盞燈在量滅之間轉(zhuǎn)換。這個(gè)燈光秀有點(diǎn)抽象哈~但是大概的意思已經(jīng)表達(dá)清楚了~如何不適用第三個(gè)變量,交換兩個(gè)變量的值這個(gè)問題經(jīng)常出現(xiàn)在校招面試中,常見的有三種解法,咱們這里只講通過位運(yùn)算的解法。首先,由異或的特性,咱們推出一個(gè)結(jié)論:1.B^B=0因?yàn)樽约汉妥约寒惢?,必然每一位都是相同的,結(jié)果自然是02.A^0=A與0異或,保持原值。那么開始我們的計(jì)算。先做一下分析:A^0=A^(B^B)=(A^B)^Bint main(void){ /* 小羽的嵌入式校招指南 */ int A = 10;//B = 1010 int B = 12; //B = 1100; printf("\nIn the beginning\nOA=%d,OB=%d\n\n",A,B); //最初的A用OA表示,最初的B用OB表示 //A = OA^OB A = A ^ B; //B = (OA^OB)^OB = OA^0 = OA B = A ^ B; //A = (OA^OB)^OA = OB^0 = OB A = A ^ B; //完成互換值 printf("\nAt the end\nA=%d,B=%d\n\n",A,B);}切記當(dāng)前的A和B代表的是原始的A和B怎樣組合起來的,就不容易搞混啦~找出唯一重復(fù)出現(xiàn)的數(shù)題:有N個(gè)數(shù),其中包含1個(gè)僅重復(fù)1次的數(shù)值和從1~N-1個(gè)不重復(fù)的數(shù)。找出該數(shù)值。例:[1,2,3,4,5,5,6,7,8,9],10個(gè)數(shù)的數(shù)組中,包含重復(fù)1次的5和不重復(fù)的12346789。答:使用該數(shù)組中的每個(gè)數(shù)與兩個(gè)包含1~N-1的不重復(fù)數(shù)組,所有數(shù)值進(jìn)行異或運(yùn)算,結(jié)果就是重復(fù)的數(shù)值。因?yàn)锳^A=0,兩個(gè)數(shù)組中重復(fù)的數(shù)值異或后得到0。而重復(fù)的數(shù)字跟0異或,得到的還是該數(shù)值。怎么樣,神奇不?如果不用異或運(yùn)算,你要怎么算呢?————————————————————更多內(nèi)容,持續(xù)更新中?。。 居X得有用的小伙伴們可以訂閱一下專欄,后續(xù)還有更多文章哦~ ?? 】作者其他專欄【嵌入式校招指南_完整學(xué)習(xí)路線】http://www.fangfengwang8.cn/creation/manager/columnDetail/MWZkkj請幫忙點(diǎn)贊、評論+收藏,是對我最大的支持~感謝?。?!