0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

C語(yǔ)言12個(gè)淺顯易懂的知識(shí)點(diǎn)

j4AI_wujianying ? 來(lái)源:未知 ? 作者:胡薇 ? 2018-06-25 09:50 ? 次閱讀

1.關(guān)于+=以及-=

這是兩個(gè)運(yùn)算符,但你否有過(guò)這種經(jīng)歷:

[cpp]view plaincopy

inttemp;

chari

for(i=0;i

{

...

temp=+2;//這里本意是每次循環(huán),temp都自增2,但是卻將'+='寫(xiě)成了'=+',按照這種寫(xiě)法,每次循環(huán)都為temp賦值正數(shù)2,與本意相差甚遠(yuǎn)

}

2. 關(guān)于意想不到的死循環(huán)

[cpp]view plaincopy

unsignedchari;

for(i=0;i<256;i++)??

{

//something

}

當(dāng)我們用上述代碼想實(shí)現(xiàn)一個(gè)小循環(huán)時(shí),結(jié)果卻事與愿違,這其實(shí)是死循環(huán)的另一種寫(xiě)法,因?yàn)闊o(wú)符號(hào)變量i最大只有255,要命的是,編譯器并不會(huì)指出這個(gè)錯(cuò)誤。

與之相類(lèi)似的代碼是:

[cpp]view plaincopy

unsignedchari;

for(i=10;i>=0;i--)

{

//something

}

這也是一個(gè)死循環(huán),你看出什么原因了嗎?無(wú)論i如何減,i都是大于等于0的。

這就告訴我們對(duì)于每個(gè)變量類(lèi)型的取值范圍要由清醒的認(rèn)識(shí)。值得注意的是相同的變量類(lèi)型對(duì)于不同的CPU構(gòu)架和不同的編譯器會(huì)有不同的結(jié)果。比如int類(lèi)型在大多數(shù)16位CPU構(gòu)架中占用兩個(gè)字節(jié),但在32位CPU中卻往往占用4個(gè)字節(jié);char類(lèi)型在絕大多數(shù)編譯器中都是有符號(hào)數(shù),但在keilMDK中卻是無(wú)符號(hào)數(shù),若是要在keilMDK下定義有符號(hào)char類(lèi)型變量,必須用signed顯式聲明。我曾讀過(guò)一本書(shū),其中有一句話:“signed關(guān)鍵字也是很寬宏大量,你也可以完全當(dāng)它不存在,在缺省狀態(tài)下,編譯器默認(rèn)數(shù)據(jù)位signed類(lèi)型”,這句話便是有異議的,我們應(yīng)該對(duì)自己所用的CPU構(gòu)架以及編譯器熟練掌握。

3. 關(guān)于'='和'=='

[cpp]view plaincopy

if(Value=0x01)

{

//something

}

當(dāng)我們判斷一個(gè)變量是否等于0x01時(shí),你是否也寫(xiě)過(guò)類(lèi)似上面的代碼?C語(yǔ)言的創(chuàng)造者認(rèn)為賦值運(yùn)算符"="出現(xiàn)的概率要遠(yuǎn)遠(yuǎn)大于等于運(yùn)算符"==",因此,我們正常邏輯中的"等于"符號(hào)(=)在C語(yǔ)言中成了賦值運(yùn)算符,而C語(yǔ)言的"等于"運(yùn)算符卻被兩個(gè)等于號(hào)(==)所代替。我之所以對(duì)這個(gè)事件耿耿于懷是因?yàn)槲以诖蠖臅r(shí)候參加的C++二級(jí)上機(jī)考試,當(dāng)我感覺(jué)很輕松的做完最后一道題后,卻發(fā)現(xiàn)運(yùn)算的結(jié)果卻與邏輯相悖,經(jīng)過(guò)調(diào)試發(fā)現(xiàn),有一個(gè)條件一直為真,我檢查了很多遍才發(fā)現(xiàn)出問(wèn)題的邏輯將等于運(yùn)算符寫(xiě)成了賦值運(yùn)算符。在if語(yǔ)句中給變量賦一個(gè)非零值,也難怪這個(gè)邏輯總是為真。

編譯器同樣不對(duì)這個(gè)問(wèn)題做出指導(dǎo)性建議,值得一提的是,如果你在Keil的if語(yǔ)句中使用了賦值運(yùn)算符,編譯器會(huì)給出警告。

避免這個(gè)問(wèn)題的一個(gè)很好的辦法是使用良好編程習(xí)慣,比如上面的代碼可寫(xiě)為:

[cpp]view plaincopy

if(0x01==Value)

{

//something

}

將常量值放到變量的前面,即使將等于運(yùn)算符寫(xiě)成賦值運(yùn)算符,編譯器也能產(chǎn)生一個(gè)語(yǔ)法錯(cuò)誤,因?yàn)閷⒁粋€(gè)變量賦值給一個(gè)常量是非法的。

4.error:#7:unrecognizedtoken

我在剛使用C語(yǔ)言以及Keil編譯器時(shí),對(duì)于這個(gè)編譯器錯(cuò)誤,有很深的印象。出現(xiàn)這個(gè)編譯錯(cuò)誤的典型代表是在敲代碼的時(shí)候輸入了中文標(biāo)點(diǎn)??!

真是讓人感慨萬(wàn)分的錯(cuò)誤!我們這些與硬件打交道的程序員,為模數(shù)電生,為PCB死,為Debug奮斗一輩子,吃需求的虧,上大小寫(xiě)的當(dāng),最后死在標(biāo)點(diǎn)上!!

5.關(guān)于字母'O'和數(shù)字'0',以及字母'l'和數(shù)字'1',在嵌入式編程中很容易和寄存器打交道,一個(gè)CPU如果有兩個(gè)相同模塊時(shí),這些模塊寄存器,往往使用數(shù)字0和數(shù)字1來(lái)區(qū)分模塊0和模塊1,比如,NXPARM7串口模塊的兩個(gè)接收緩沖寄存器分別為:U0RBR和U1RBR,要命的是在鍵盤(pán)上字母O和數(shù)字0相距的還那么近,你是否也有將上述寄存器寫(xiě)成UORBR和UlRBR的經(jīng)歷,我是曾經(jīng)在這方面糾結(jié)過(guò)一次,好在編譯器能指出這個(gè)未定義的字符串。

6.sizeof()

不知道有多少人和我曾經(jīng)一樣,將這個(gè)關(guān)鍵字認(rèn)為是一個(gè)庫(kù)函數(shù)。

[cpp]view plaincopy

inti,j;

j=sizeof(i);//對(duì)于這一句,當(dāng)初壓根沒(méi)把它往關(guān)鍵字上想,這家伙偽裝的實(shí)在夠好。

既然提到它,不如多說(shuō)一下,sizeof在計(jì)算變量所占空間大小時(shí),括號(hào)可以省略,而計(jì)算類(lèi)型大小時(shí),不能省略。什么意思呢?還是上面的變量聲明,可以寫(xiě)成j=sizeof(i)也可以寫(xiě)成j=sizeofi,因?yàn)檫@是計(jì)算變量所占空間大?。豢梢詫?xiě)成j=sizeof(int),但不可以寫(xiě)成j=sizeofint,因?yàn)檫@是計(jì)算數(shù)據(jù)類(lèi)型大小。

總體來(lái)說(shuō),關(guān)鍵字sizeof的具有一定的變態(tài)基礎(chǔ)的,在我還是小白的時(shí)候,曾經(jīng)為下面的一道題傷過(guò)腦袋:

下面代碼里,假設(shè)在32位系統(tǒng)下,個(gè)sizeof計(jì)算的結(jié)果分別是多少?

int*p=NULL;

sizeof(p)的值是:

sizeof(*p)的值是:

inta[100]

sizeof(a)的值是:

sizeof(a[100])的值是:

sizeof(&a)的值是:

sizeof(&a[0])的值是:

intb[100];

voidfun(intb[100])

{

sizeof(b);

}

sizeof(b)的值為:

7 關(guān)于數(shù)組越界

[cpp]view plaincopy

inta[30];

for(i=30;i>0;i--)

{

a[i]=something;

}

這是個(gè)典型的數(shù)組越界例子,最近我同事的一個(gè)程序中便出現(xiàn)了。不知道有多少同學(xué)遇到或?qū)⒁龅綌?shù)組越界問(wèn)題,即便你定義了30個(gè)數(shù)組a[30],你也不可以為a[30]賦值,因?yàn)橄聵?biāo)為30的元素已經(jīng)越界了。所以說(shuō)數(shù)組下標(biāo)定義的很奇特,它是從0開(kāi)始的。但當(dāng)我們還是新手的時(shí)候,最容易忽視這一點(diǎn)。幸好現(xiàn)在的有些編譯器會(huì)對(duì)這個(gè)越界產(chǎn)生警告信息

8. 關(guān)于宏

[cpp]view plaincopy

#defineMAX_TAST4;

這個(gè)錯(cuò)誤編譯器會(huì)指出的,即便這樣,相信很多同學(xué)在最初的時(shí)候也不會(huì)在第一時(shí)間發(fā)現(xiàn)這句代碼的最后多了一個(gè)分號(hào)。這個(gè)分號(hào)會(huì)導(dǎo)致一些編譯器報(bào)錯(cuò),因?yàn)楹甓x的結(jié)尾并不需要分號(hào)。

同樣與define有關(guān)的是這樣一句:#define"config.h",我便吃過(guò)類(lèi)似暗虧,在編譯器的提示之下,看了幾遍才發(fā)現(xiàn)頭文件包含應(yīng)該是#include"config.h"。

既然提到#define,還是說(shuō)說(shuō)它需要注意的幾個(gè)點(diǎn),也是經(jīng)常在資料上被提及的。

a.使用#define時(shí),括號(hào)一定要足夠。比如定義一個(gè)宏函數(shù),求x的平方:

[cpp]view plaincopy

#defineSQR(x)x*x..............1

或者這樣寫(xiě):

[cpp]view plaincopy

#defineSQR(x)(x)*(x)...............2

上面兩種都是有風(fēng)險(xiǎn)的,對(duì)于第一種定義,SQR(10+1)就會(huì)得到和我們的設(shè)想不一致的結(jié)果;第二種SQR(5*3)*SQR(5*3)也會(huì)得到和我們?cè)O(shè)想不一致的結(jié)果,因此更安全的定義方法是:

[cpp]view plaincopy

#defineSQR(x)((x)*(x))

b.使用#define的時(shí)候,,意空格的使用。比如下面的例子:

[cpp]view plaincopy

#defineSQR(x)((x)*(x))

這已經(jīng)不是SQR(x)函數(shù)了,編譯器會(huì)把認(rèn)為定義了一個(gè)宏SQR,代表(x)((x)*(x)),因?yàn)镾QR與(x)之間有空格。這點(diǎn)需要注意。

c.使用'#'在字符串中包含宏參數(shù)。比如下面的例子:

[cpp]view plaincopy

#defineSQR(x)printf("Thesquareofxis%d.\n",((x)*(x))")

[cpp]view plaincopy

如果這樣使用宏:

[cpp]view plaincopy

SQR(8)

則輸出為:

Thesquareofxis64.

這個(gè)時(shí)候引號(hào)中的x被當(dāng)做字符串來(lái)處理了,而不是一個(gè)可以被宏參數(shù)替換的符號(hào).如果你想在字符中的x也被宏參數(shù)替換,可以這么來(lái)定義宏:

[cpp]view plaincopy

#defineSQR(x)printf("Thesquareof"#x"is%d.\n",((x)*(x))")

這樣得到的結(jié)果為:

Thesquareof8is64.

上面的這些例子,恐怕是網(wǎng)上隨處可見(jiàn)的,但真的會(huì)這么用卻有待考證。下面給出一個(gè)我自己遇到的不加括號(hào)產(chǎn)生錯(cuò)誤的例子。在嵌入式編程中,遇到讀取IO端口某一位的電平狀態(tài)的場(chǎng)合是在平常不過(guò)的了,比如在NXP的ARM7中,讀取端口P0.11的電平狀態(tài)并判斷是否為高電平,代碼如下:

[cpp]view plaincopy

#defineREADSDAIO0PIN&(1<<11)????????????//定義宏,讀IO口p0.11的端口狀態(tài),但并未使用足夠多的括號(hào)??

//判斷p0.11端口是否為高電平,使用下述語(yǔ)句就是錯(cuò)誤的:

if(READSDA==(1<<11))??

{

//是高電平,處理高電平的問(wèn)題

}

編譯器在編譯后將宏帶入,原if語(yǔ)句變?yōu)椋?/p>

[cpp]view plaincopy

if(IO0PIN&(1<<11)?==(1<<11))??

{

//是高電平,處理高電平的問(wèn)題

}

這樣的話,運(yùn)算符'=='的優(yōu)先級(jí)是大于'&'的,從而IO0PIN&(1<<11)?==(1<<11))語(yǔ)句等效為IO0PIN&0x00000001,相當(dāng)于判斷P0.1是否為高電平,與原意相差甚遠(yuǎn).

9.數(shù)組和指針

在32位系統(tǒng)下,

定義一個(gè)數(shù)組:

[cpp]view plaincopy

inta[10]={1,2,3,4,5,6,7,8,9,0};

定義一個(gè)指針:

[cpp]view plaincopy

int*p;

那么,a、a[0]、&a、&a[0]各表示什么意思?

那么,sizeof(a)、sizeof(a[0])、sizeof(&a)、sizeof(&a[0])的值各是什么?

如果,對(duì)指針p賦值:

p=a;

并且通過(guò)編譯器仿真,得知現(xiàn)在p等于a等于0x00000200,

那么,a+1=?

&a+1=?

p+1=?

p[2]=?

*(p+2)=?

*(a+2)=?

再如果

[cpp]view plaincopy

int*ptr=(int*)(&a+1);

那,*(ptr-1)=?

世上最曖昧、最糾纏不清的,莫過(guò)于數(shù)組名和指針。這一方面源于大學(xué)的教材并沒(méi)有重視這一塊,也源于教學(xué)時(shí)硬生生的將C語(yǔ)言和硬件分開(kāi)。一方面,教材和教這一門(mén)的老師在開(kāi)始時(shí)便向我們灌輸了“數(shù)組名和指針很像,可以等同”的思想;另一方面,在學(xué)C語(yǔ)言的時(shí)候,并沒(méi)有系統(tǒng)的學(xué)過(guò)計(jì)算機(jī)硬件(尋址、存儲(chǔ)、匯編),C語(yǔ)言是一個(gè)很接近硬件的高級(jí)語(yǔ)言,如果沒(méi)有處理器(包括單片機(jī)微處理器)的基礎(chǔ)知識(shí),會(huì)導(dǎo)致非常多的同學(xué)怎么都理解不透C語(yǔ)言的指針和數(shù)組。

當(dāng)我們定義一個(gè)數(shù)組inta[10]時(shí),編譯器會(huì)分配一塊內(nèi)存,這塊內(nèi)存的名字命名為a,這個(gè)a只是一個(gè)名字,只是方便編譯器和編程者使用,編譯器并不為這個(gè)名字分配空間來(lái)存儲(chǔ)它。我們可以用a[0]、a[1]來(lái)訪問(wèn)數(shù)組內(nèi)的元素。a作為右值(位于等號(hào)的右邊)時(shí),表示的是數(shù)組第一個(gè)元素的地址(意義與&a[0]一樣,但&a[0]是一個(gè)指針變量,編譯器會(huì)為他分配空間,a卻不一樣,編譯器并不為它分配什么空間),而并非數(shù)組首地址,&a才表示數(shù)組的首地址。

所以,第一個(gè)問(wèn)題,a是這個(gè)數(shù)組所在的內(nèi)存的名字,當(dāng)它為右值時(shí),表示數(shù)組首元素的地址,a[0]是數(shù)組的第一個(gè)元素,其值等于1,&a是整個(gè)數(shù)組的首地址,它是一個(gè)指針;&a[0]是數(shù)組首元素的地址,它的值和a做右值時(shí)一樣,但意義不同,因?yàn)?a[0]是一個(gè)指針,編譯器要為它分配存儲(chǔ)空間,但a卻不會(huì)被分配存儲(chǔ)空間,a也不是指針型變量。

明白了上面那些,關(guān)于sizeof的計(jì)算也就不會(huì)困難了:

sizeof(a)=4*10=40,因?yàn)閍代表的是整塊數(shù)組內(nèi)存;

sizeof(a[0])=4,這相當(dāng)于計(jì)算int的大小,在32位系統(tǒng)下,int占4個(gè)字節(jié)。

sizeof(&a)和sizeof(&a[0])都是計(jì)算指針變量的大小,在32位系統(tǒng)下,指針變量占4個(gè)字節(jié)。

對(duì)于最后一個(gè)問(wèn)題,涉及到指針的加減。

指針的加減中有一個(gè)重要的原則就是它的加減跟我們普通意義上的加減不是一個(gè)概念,它是按指針?biāo)割?lèi)型的內(nèi)存大小來(lái)進(jìn)行加減的。當(dāng)我還是一個(gè)新手的時(shí)候,對(duì)于p++、p+1這類(lèi)指針運(yùn)算的含義超出了我的意料之外,在上例中,若是p=0x00000200,那么p++運(yùn)算之后的p值應(yīng)該為0x00000204。有多少同學(xué),曾經(jīng)把它計(jì)算成0x00000201!

數(shù)組名a在做計(jì)算的時(shí)候表示數(shù)組首元素的地址,這時(shí)候a等于0x00000200,所以a+1等于0x00000200+4=0x00000204,因?yàn)橐粋€(gè)int型在32位系統(tǒng)下占用4個(gè)字節(jié)。&a是整個(gè)數(shù)組的首地址,&a+1=0x00000200+4*10=0x00000228。

其它的也都比較好理解,p+1=0x00000200+04=0x00000204、p[2]=3、*(p+2)=3、*(ptr-1)=0.

10.3/(-3)=?

3%(-2)=?

(-3)%2=?

拋開(kāi)它是否有實(shí)際的意義,這個(gè)看似簡(jiǎn)單的語(yǔ)句,不知道有多少同學(xué)不確定結(jié)果到底是什么。

其實(shí)大多數(shù)的編譯器遵循這樣一個(gè)規(guī)定:余數(shù)與被除數(shù)的正負(fù)號(hào)相同,被除數(shù)等于結(jié)果乘以除數(shù)加上余數(shù)。所以,以上的三個(gè)結(jié)果分別為-1、1、-1。

11.指針數(shù)組與數(shù)組指針

有一段時(shí)間,我怎么都不能區(qū)分指針數(shù)組和數(shù)組指針,就像下面的聲明:

[cpp]view plaincopy

int*p1[10];

int(*p2)[10];

首先,要來(lái)解釋一下什么是指針數(shù)組,什么是數(shù)組指針:指針數(shù)組首先是一個(gè)數(shù)組,它的成員都是指針型變量;數(shù)組指針首先是一個(gè)指針,這個(gè)指針指向一個(gè)數(shù)組(它的值和數(shù)組名表示的值一樣,只是數(shù)組指針是一個(gè)變量,編譯器要為它分配存儲(chǔ)空間,但數(shù)組名類(lèi)似于一個(gè)常亮,是編譯器在編譯階段就確定好的一個(gè)值,編譯器不會(huì)為它分配存儲(chǔ)空間)。

對(duì)于p1,由于中括號(hào)的優(yōu)先級(jí)(關(guān)于優(yōu)先級(jí),后面會(huì)專(zhuān)門(mén)提起)是大于*的,所以p1首先與'[]'相結(jié)合,構(gòu)成一個(gè)數(shù)組,在這個(gè)數(shù)組之前又有一個(gè)'*'運(yùn)算符,說(shuō)明這是定義一個(gè)指針數(shù)組(int*a:定義一個(gè)指針a,這里可以將p1[10]替換成a,就不難理解了),數(shù)組的元素都是指向int型的指針。

對(duì)于p2,'()'雖然與'[]'為同一優(yōu)先級(jí),但卻是表達(dá)式結(jié)合方向從左到右結(jié)合的,所以編譯器會(huì)先處理(*p2),這是典型的定義一個(gè)指針,只不過(guò)這個(gè)指針指向一個(gè)包含10個(gè)int型數(shù)據(jù)的內(nèi)存塊。為了加強(qiáng)理解,這里給出兩個(gè)相同原理的函數(shù)聲明:

void*p1(void);----------------------聲明1,定義一個(gè)返回值是void類(lèi)型指針的函數(shù)p1

void(*p2)(void);-----------------------聲明2,定義一個(gè)函數(shù)指針,該函數(shù)不返回任何值

有了上面的鋪墊,現(xiàn)在定義一個(gè)高級(jí)C語(yǔ)言編程技巧中常用的函數(shù)指針數(shù)組應(yīng)該很容易了吧!首先這是一個(gè)數(shù)組,數(shù)組的元素是指向一個(gè)函數(shù)的指針,以定義一個(gè)參數(shù)為空,返回值為int類(lèi)型的函數(shù)指針數(shù)組p1為例:

[cpp]view plaincopy

int(*p1[5])(void);

分析如下:

定義一個(gè)返回值為int類(lèi)型的函數(shù)指針p1應(yīng)該是:

[cpp]view plaincopy

int(*p1)(void);

那么將這類(lèi)指針?lè)诺揭粋€(gè)數(shù)組中不正是我們需要的定義嗎,套用指針數(shù)組的定義方法,返回值為int類(lèi)型函數(shù)指針數(shù)組定義為:int(*p1[5])(void);

12.運(yùn)算符的優(yōu)先級(jí)

C語(yǔ)言有32個(gè)關(guān)鍵字卻有44個(gè)運(yùn)算符!運(yùn)算符之間有固定的優(yōu)先級(jí),雖然它們可以分成15類(lèi)優(yōu)先級(jí),但如果讓一個(gè)程序員完全記住這些運(yùn)算符之間的優(yōu)先級(jí)關(guān)系,怕是老手也是不容易的吧。如果你的程序只是語(yǔ)法錯(cuò)誤,這類(lèi)錯(cuò)誤是最容易解決的,編譯器就會(huì)幫你檢測(cè)出來(lái);如果是你自己的邏輯出現(xiàn)錯(cuò)誤,那么根據(jù)運(yùn)行結(jié)果仔細(xì)檢查一下代碼可能也不難發(fā)現(xiàn);但若是你的邏輯正確卻記錯(cuò)了運(yùn)算符的優(yōu)先級(jí)關(guān)系,導(dǎo)致程序運(yùn)行結(jié)果和你設(shè)想的不同,這種錯(cuò)誤就很難查出了,因?yàn)樵谀愕臐撘庾R(shí)里,已經(jīng)把這種錯(cuò)誤點(diǎn)當(dāng)成理所當(dāng)然不用關(guān)注的。

請(qǐng)看下面一句代碼代表什么意思:

[cpp]view plaincopy

*string++;

由于*和++但是單目運(yùn)算符,優(yōu)先級(jí)相同,但結(jié)合方向卻是自右向左,那么*string++應(yīng)該就是*(string++),取出當(dāng)前字符后將指針后移。不知道有沒(méi)有人把它認(rèn)為是(*string)++,即取指針string所指向的對(duì)象,然后將該對(duì)象增1.

我曾經(jīng)在代碼中不止一次的出現(xiàn)過(guò)因?yàn)閮?yōu)先級(jí)問(wèn)題而導(dǎo)致的程序邏輯錯(cuò)誤,那個(gè)時(shí)候我并沒(méi)有完整的記過(guò)優(yōu)先級(jí),二十使用了一種“偷巧”的方法:只是簡(jiǎn)單記住前幾級(jí)優(yōu)先級(jí),其它自己沒(méi)把握的一律使用括號(hào)。這種方法我現(xiàn)在是不推薦的,一是因?yàn)榇罅康睦ㄌ?hào)影響代碼閱讀和程序的簡(jiǎn)潔,二是總有時(shí)候我們稍微一松懈,就忘記了加括號(hào),而后一種情況,正是很多人可能會(huì)遇到的。比如下面一句代碼,無(wú)符號(hào)8位變量ucTimeValue中存放十進(jìn)制編碼的數(shù)據(jù)23,我想將十進(jìn)制編碼轉(zhuǎn)成16進(jìn)制編碼,代碼為:

[cpp]view plaincopy

temp8=(ucTimeValue>>4)*10+ucTimeValue&0x0F;//十進(jìn)制轉(zhuǎn)化為16進(jìn)制,但忽略了運(yùn)算符'+'的優(yōu)先級(jí)是大于運(yùn)算符'&'的

像這類(lèi)代碼編譯肯定可以通過(guò),但運(yùn)行的結(jié)果卻出乎我的意料,而且由于我先入為主的錯(cuò)誤思想,要在一大段代碼中發(fā)現(xiàn)這個(gè)錯(cuò)誤著實(shí)要花費(fèi)一番功夫。

再例如,如果我想判斷一個(gè)寄存器的某一位是否為零,假如是判斷寄存器IO0SET的bit17是否為零,但代碼卻寫(xiě)成了這樣:

[cpp]view plaincopy

if(IO0SET&(1<<17)==0)???

這樣寫(xiě)其實(shí)是得不到正確的結(jié)果的,因?yàn)槲液雎粤?=="的優(yōu)先級(jí)是大于"&"的.按照上面的代碼分析:因?yàn)?=="的優(yōu)先級(jí)大于"&",所以程序先判斷(1<<17)是否等于0?發(fā)現(xiàn)這是不相等的,所以(1<<17)==0表達(dá)式的值為假,即為0,0與(&)上任何一個(gè)數(shù)都是0,所以IO0SET&(1<<17))==0整個(gè)表達(dá)式的值永遠(yuǎn)為0,這與原意相差甚遠(yuǎn)。?

按照原意,應(yīng)該這樣寫(xiě):

[cpp]view plaincopy

if((IO0SET&(1<<17)))==0)??

其實(shí),運(yùn)算符的優(yōu)先級(jí)是有一定的規(guī)律可循的,下面給出優(yōu)先級(jí)口訣(注:口訣來(lái)源于互聯(lián)網(wǎng))

優(yōu)先級(jí)口訣

括號(hào)成員第一; 括號(hào)運(yùn)算符[]()成員運(yùn)算符.->

全體單目第二; 所有的單目運(yùn)算符比如++--+(正)-(負(fù))指針運(yùn)算*&

乘除余三,加減四; 這個(gè)"余"是指取余運(yùn)算即%

移位五,關(guān)系六; 移位運(yùn)算符:<>,關(guān)系:>=<=?等

等于(與)不等排第七; 即==!=

位與異或和位或; 這幾個(gè)都是位運(yùn)算:位與(&)異或(^)位或(|)

"三分天下"八九十;

邏輯或跟與; 邏輯運(yùn)算符:||和&&

十二和十一; 注意順序:優(yōu)先級(jí)(||)底于優(yōu)先級(jí)(&&)

條件高于賦值, 三目運(yùn)算符優(yōu)先級(jí)排到13位只比賦值運(yùn)算符和","高

逗號(hào)運(yùn)算級(jí)最低! 逗號(hào)運(yùn)算符優(yōu)先級(jí)最低

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • C語(yǔ)言
    +關(guān)注

    關(guān)注

    180

    文章

    7581

    瀏覽量

    135582
  • 編譯器
    +關(guān)注

    關(guān)注

    1

    文章

    1608

    瀏覽量

    48979

原文標(biāo)題:曾讓我哭笑不得抓狂的C語(yǔ)言

文章出處:【微信號(hào):wujianying_danpianji,微信公眾號(hào):?jiǎn)纹瑱C(jī)精講吳鑒鷹】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    一些小眾的C語(yǔ)言知識(shí)點(diǎn)

    一些小眾的C語(yǔ)言知識(shí)點(diǎn),可能會(huì)比較有趣或者怪異,分享給大家看一下。
    發(fā)表于 09-26 10:16 ?625次閱讀

    嵌入式C語(yǔ)言知識(shí)點(diǎn)總結(jié)

    怎么才能做好嵌入式開(kāi)發(fā)?學(xué)好C語(yǔ)言吧!今天就來(lái)推薦一篇大佬寫(xiě)的嵌入式C語(yǔ)言知識(shí)點(diǎn)總結(jié)。
    發(fā)表于 09-27 09:53 ?1145次閱讀

    C語(yǔ)言鏈表知識(shí)點(diǎn)(2)

    C語(yǔ)言鏈表知識(shí)點(diǎn)(2)
    發(fā)表于 08-22 10:38 ?281次閱讀
    <b class='flag-5'>C</b><b class='flag-5'>語(yǔ)言</b>鏈表<b class='flag-5'>知識(shí)點(diǎn)</b>(2)

    C51單片機(jī)及C語(yǔ)言知識(shí)點(diǎn)必備秘籍

      電子發(fā)燒友網(wǎng)訊:應(yīng)廣大電子發(fā)燒友網(wǎng)讀者要求,本電子書(shū)《C51單片機(jī)及C語(yǔ)言知識(shí)點(diǎn)必備秘籍》為《單片機(jī)關(guān)鍵知識(shí)點(diǎn)全攻略》單片機(jī)系列教程及《
    發(fā)表于 07-30 13:59 ?9795次閱讀

    【信盈達(dá)】C語(yǔ)言知識(shí)點(diǎn)的總結(jié)

    、算法說(shuō)明:學(xué)習(xí)單片機(jī)C一般只需要前9個(gè)知識(shí)點(diǎn)即可進(jìn)行產(chǎn)品開(kāi)發(fā),但要學(xué)習(xí)嵌入式C還需要要掌握:指針、結(jié)構(gòu)體、鏈表、宏定義等知識(shí)點(diǎn)。二、單片機(jī)
    發(fā)表于 10-08 14:41

    C語(yǔ)言程序小知識(shí)點(diǎn)總結(jié)

    C語(yǔ)言總結(jié)(stm32嵌入式開(kāi)發(fā))文章目錄C語(yǔ)言總結(jié)(stm32嵌入式開(kāi)發(fā))c程序小知識(shí)點(diǎn)總結(jié)1
    發(fā)表于 11-05 07:45

    淺顯易懂的方式帶你敲開(kāi)Linux驅(qū)動(dòng)開(kāi)發(fā)的大門(mén)

    # 前言開(kāi)發(fā)過(guò)單片機(jī)的小伙伴可以看下我之前的一篇文章從單片機(jī)開(kāi)發(fā)到linux內(nèi)核驅(qū)動(dòng),以淺顯易懂的方式帶你敲開(kāi)Linux驅(qū)動(dòng)開(kāi)發(fā)的大門(mén)。# 正文用戶空間的每個(gè)函數(shù)(用于使用設(shè)備或者文件的),在內(nèi)
    發(fā)表于 01-19 08:31

    RT-Thread嵌入式實(shí)時(shí)多線程操作系統(tǒng)介紹

    的自主知識(shí)產(chǎn)權(quán)。經(jīng)過(guò)近12個(gè)年頭的沉淀,伴隨著物聯(lián)網(wǎng)的興起,它正演變成一個(gè)功能強(qiáng)大、組件豐富的物聯(lián)網(wǎng)操作系統(tǒng)。RT-Thread的官網(wǎng)。讀者可以在官網(wǎng)上看到許多RT-Thread的相關(guān)
    發(fā)表于 02-17 07:13

    解析甄別人工智能泡沫淺顯易懂的方法

    不過(guò),這套方法論對(duì)用戶可能并不適用,畢竟并無(wú)這樣的專(zhuān)業(yè)知識(shí)和經(jīng)驗(yàn)積累。所以,面對(duì)市面上林林總總的人工智能產(chǎn)品,要不要掏錢(qián)包,還得有淺顯易懂的甄別人工智能泡沫的方法。
    的頭像 發(fā)表于 01-09 10:43 ?2266次閱讀

    C51語(yǔ)言的基礎(chǔ)知識(shí)點(diǎn)實(shí)例講解

    本文檔的主要內(nèi)容詳細(xì)介紹的是C51語(yǔ)言的18個(gè)基礎(chǔ)知識(shí)點(diǎn)實(shí)例講解包括了:C51控制語(yǔ)句和C51數(shù)
    發(fā)表于 06-04 17:52 ?12次下載
    <b class='flag-5'>C</b>51<b class='flag-5'>語(yǔ)言</b>的基礎(chǔ)<b class='flag-5'>知識(shí)點(diǎn)</b>實(shí)例講解

    C語(yǔ)言學(xué)習(xí)入門(mén)知識(shí)點(diǎn)/干貨

    C語(yǔ)言知識(shí)點(diǎn)總結(jié)
    的頭像 發(fā)表于 07-18 17:54 ?5841次閱讀
    <b class='flag-5'>C</b><b class='flag-5'>語(yǔ)言</b>學(xué)習(xí)入門(mén)<b class='flag-5'>知識(shí)點(diǎn)</b>/干貨

    STM32中重要的C語(yǔ)言知識(shí)點(diǎn)總結(jié)

    的一些例程中,遇到不懂的C語(yǔ)言知識(shí),再去查相關(guān)的知識(shí)點(diǎn),這樣印象才會(huì)深刻些。 下面就列出了一些STM32中重要的C
    的頭像 發(fā)表于 04-25 16:42 ?2724次閱讀
    STM32中重要的<b class='flag-5'>C</b><b class='flag-5'>語(yǔ)言</b><b class='flag-5'>知識(shí)點(diǎn)</b>總結(jié)

    嵌入式C語(yǔ)言知識(shí)點(diǎn)總結(jié)

    導(dǎo)讀:怎么做好嵌入式?相信這個(gè)問(wèn)題無(wú)論問(wèn)誰(shuí)你都會(huì)得到一句學(xué)好C語(yǔ)言!今天推薦一篇大佬寫(xiě)的嵌入式C語(yǔ)言知識(shí)點(diǎn)總結(jié),非常值得一讀。
    的頭像 發(fā)表于 04-13 11:12 ?2636次閱讀

    C語(yǔ)言C++面試知識(shí)點(diǎn)總結(jié)

    相對(duì)而言,C語(yǔ)言C++相關(guān)的面試題比較少見(jiàn),沒(méi)有Java方向?qū)懙娜四敲炊?,這是一篇 C 語(yǔ)言C
    的頭像 發(fā)表于 05-13 11:59 ?1793次閱讀

    C語(yǔ)言最重要的知識(shí)點(diǎn)

    C語(yǔ)言知識(shí)點(diǎn)總結(jié).doc
    發(fā)表于 02-16 16:37 ?8次下載