日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

C陷阱与缺陷代码分析之第2章语法陷阱

發(fā)布時(shí)間:2025/3/15 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C陷阱与缺陷代码分析之第2章语法陷阱 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

作者:劉昊昱?

博客:http://blog.csdn.net/liuhaoyutz

?

陷阱1 理解函數(shù)聲明

作者提出一個(gè)問題:有一個(gè)首地址為0的函數(shù),該函數(shù)返回值類型為void,沒有參數(shù)。怎樣用C語言的語句調(diào)用這個(gè)函數(shù)?

答案是(*(void? (*)())0)();

?

要理解這個(gè)調(diào)用形式,要清楚如下兩個(gè)問題:

一是函數(shù)指針。

假設(shè)fp是一個(gè)函數(shù)指針,則調(diào)用fp所指向的函數(shù)的方法是

(*fp)();

因?yàn)閒p是一個(gè)函數(shù)指針,所以*fp是該指針?biāo)赶虻暮瘮?shù),所以(*fp)()就是調(diào)用該函數(shù)的方式。ANSI C允許將(*fp)()簡寫為fp(),fp()也是我們比較常見的形式,但是一定要知道這種寫法是一種簡寫形式。例如prinf()函數(shù),printf就是函數(shù)指針,它的完整形式是(*printf)()。為了說明這個(gè)問題,我們來看一個(gè)測試程序page17.c,代碼如下:

?

1#include <stdio.h> 2 3int main() 4{ 5 printf("test1\n"); 6 (*printf)("test2\n"); 7 8 return 0; 9}

?

?

編譯運(yùn)行結(jié)果如下:

?

二是強(qiáng)制類型轉(zhuǎn)換符的聲明方式。

某類型的強(qiáng)制類型轉(zhuǎn)換符,只需要把該類型變量聲明中的變量名和聲明末尾的分號(hào)去掉,再將剩余的部分用一個(gè)括號(hào)封裝起來即可。例如,聲明一個(gè)int型指針變量的方式是

int *p;

按照上面的原則,int型指針強(qiáng)制類型轉(zhuǎn)換符就是把變量名p和末尾的分號(hào)去掉,再把剩余的部分用一個(gè)括號(hào)封裝起來,即(int *)。

同理,聲明一個(gè)返回值為void,沒有參數(shù)的函數(shù)指針變量f的方式是:

void (*f)();

按照上面的原則,返回值為void,沒有參數(shù)的函數(shù)指針類型強(qiáng)制轉(zhuǎn)換符就是把變量名f和最后的分號(hào)去掉,再把剩余的部分用一個(gè)括號(hào)封裝起來,即(void (*)())。

?

有了上面的預(yù)備知識(shí),我們可以來看作者提出的問題了。首地址為0的函數(shù),也就是函數(shù)指針的值為0,函數(shù)返回值類型為void,沒有參數(shù)。所以我們把0強(qiáng)制轉(zhuǎn)換為(void (*)())類型就是該函數(shù)的函數(shù)指針,有了函數(shù)指針,要調(diào)用該函數(shù),則是(*(void (*)())0)();

如果使用typedef能夠使表述更加清晰:

typedef void (*funcptr)();

(*(funcptr)0)();

?

作者舉的第二個(gè)例子是signal函數(shù),其函數(shù)聲明如下:

void (*signal(int, void(*)(int)))(int);

怎樣來理解這個(gè)函數(shù)聲明呢?

signal函數(shù)有兩個(gè)參數(shù),第一個(gè)參數(shù)是一個(gè)整數(shù),代表需要“被捕獲”的特定信號(hào)。第二個(gè)參數(shù)是一個(gè)函數(shù)指針,它是信號(hào)處理函數(shù)指針,它的返回值類型為void,該信號(hào)處理函數(shù)同樣有一個(gè)int型參數(shù)代表要處理的信號(hào)。

讓我們從信號(hào)處理函數(shù)開始,信號(hào)處理函數(shù)的函數(shù)指針聲明如下:

void (*sfp)(int);

信號(hào)處理函數(shù)指針類型可以通過把指針變量名sfp和最后的分號(hào)去掉得到,即:

void (*)(int)

signal函數(shù)的返回值是原來的信號(hào)處理函數(shù)指針,即singnal函數(shù)的返回值類型是void(*)(int)。

綜上所述可知,signal函數(shù)的聲明形式應(yīng)該是:

void (*signal(int, void(*)(int)))(int);

同樣地,使用typedef可以簡化signal函數(shù)的聲明:

typedef void (*HANDLER)(int);

HANDLER signal (int, HANDLER);

?

陷阱二運(yùn)算符的優(yōu)先級(jí)

記住C語言運(yùn)算符的優(yōu)先級(jí)是非常有益的,但是,C語言運(yùn)算符優(yōu)先級(jí)多達(dá)15個(gè),記住它們并不是一件容易的事。完整的C語言運(yùn)算符優(yōu)先級(jí)如下表所示:

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

運(yùn)算符

名稱或含義

使用形式

結(jié)合方向

說明

1

[]

數(shù)組下標(biāo)

數(shù)組名[常量表達(dá)式]

左到右

()

圓括號(hào)

(表達(dá)式)/函數(shù)名(形參表)

.

成員選擇(對(duì)象)

對(duì)象.成員名

->

成員選擇(指針)

對(duì)象指針->成員名

2

-

負(fù)號(hào)運(yùn)算符

-表達(dá)式

右到左

單目運(yùn)算符

(類型)

強(qiáng)制類型轉(zhuǎn)換

(數(shù)據(jù)類型)表達(dá)式

++

自增運(yùn)算符

++變量名/變量名++

單目運(yùn)算符

--

自減運(yùn)算符

--變量名/變量名--

單目運(yùn)算符

*

取值運(yùn)算符

*指針變量

單目運(yùn)算符

&

取地址運(yùn)算符

&變量名

單目運(yùn)算符

!

邏輯非運(yùn)算符

!表達(dá)式

單目運(yùn)算符

~

按位取反運(yùn)算符

~表達(dá)式

單目運(yùn)算符

sizeof

長度運(yùn)算符

sizeof(表達(dá)式)

3

/

表達(dá)式/表達(dá)式

左到右

雙目運(yùn)算符

*

表達(dá)式*表達(dá)式

雙目運(yùn)算符

%

余數(shù)(取模)

整型表達(dá)式/整型表達(dá)式

雙目運(yùn)算符

4

+

表達(dá)式+表達(dá)式

左到右

雙目運(yùn)算符

-

表達(dá)式-表達(dá)式

雙目運(yùn)算符

5

<<?

左移

變量<<表達(dá)式

左到右

雙目運(yùn)算符

>>?

右移

變量>>表達(dá)式

雙目運(yùn)算符

6

>?

大于

表達(dá)式>表達(dá)式

左到右

雙目運(yùn)算符

>=

大于等于

表達(dá)式>=表達(dá)式

雙目運(yùn)算符

<?

小于

表達(dá)式<表達(dá)式

雙目運(yùn)算符

<=

小于等于

表達(dá)式<=表達(dá)式

雙目運(yùn)算符

7

==

等于

表達(dá)式==表達(dá)式

左到右

雙目運(yùn)算符

!=

不等于

表達(dá)式!= 表達(dá)式

雙目運(yùn)算符

8

&

按位與

表達(dá)式&表達(dá)式

左到右

雙目運(yùn)算符

9

^

按位異或

表達(dá)式^表達(dá)式

左到右

雙目運(yùn)算符

10

|

按位或

表達(dá)式|表達(dá)式

左到右

雙目運(yùn)算符

11

&&

邏輯與

表達(dá)式&&表達(dá)式

左到右

雙目運(yùn)算符

12

||

邏輯或

表達(dá)式||表達(dá)式

左到右

雙目運(yùn)算符

13

?:

條件運(yùn)算符

表達(dá)式1? 表達(dá)式2: 表達(dá)式3

右到左

三目運(yùn)算符

14

=

賦值運(yùn)算符

變量=表達(dá)式

右到左

/=

除后賦值

變量/=表達(dá)式

*=

乘后賦值

變量*=表達(dá)式

%=

取模后賦值

變量%=表達(dá)式

+=

加后賦值

變量+=表達(dá)式

-=

減后賦值

變量-=表達(dá)式

<<=

左移后賦值

變量<<=表達(dá)式

>>=

右移后賦值

變量>>=表達(dá)式

&=

按位與后賦值

變量&=表達(dá)式

^=

按位異或后賦值

變量^=表達(dá)式

|=

按位或后賦值

變量|=表達(dá)式

15

,

逗號(hào)運(yùn)算符

表達(dá)式,表達(dá)式,…

左到右

從左向右順序運(yùn)算

如果把這些運(yùn)算符恰當(dāng)分組,并且理解了各組運(yùn)算符之間的相對(duì)優(yōu)先級(jí),那么這張表其實(shí)不難記住。

第一:

優(yōu)先級(jí)最高者其實(shí)并不是真正意義上的運(yùn)算符,包括:數(shù)組下標(biāo)、函數(shù)調(diào)用操作符,結(jié)構(gòu)成員選擇符。它們的優(yōu)先級(jí)是1級(jí),都是自左向右結(jié)合,因此a.b.c的含義是(a.b).c,而不是a.(b.c)。

第二:

單目運(yùn)算符的優(yōu)先級(jí)僅次于前述運(yùn)算符,它們的優(yōu)先級(jí)是2級(jí)。在所有真正意義上的運(yùn)算符中,它們的優(yōu)先級(jí)最高。單目運(yùn)算符是從右向左結(jié)合的,因此*p++會(huì)被編譯器解釋成*(p++),即取指針p所指向的對(duì)象,然后將p遞增1,而不是(*p)++,即取指針p所指向的對(duì)象,然后將該對(duì)象的值加1。

第三:

優(yōu)先級(jí)比單目運(yùn)算符低的,接下來就是雙目運(yùn)算符。

在雙目運(yùn)算符中,算術(shù)運(yùn)算符優(yōu)先級(jí)最高(乘、除、取余為3級(jí),加、減為4級(jí)),

移位運(yùn)算符次之(左移>>、右移<<,為5級(jí)),

關(guān)系運(yùn)算符再次之(如>、<、<=等等,為6級(jí),==和!=,為7級(jí)),

接著是邏輯運(yùn)算符(如按位與&、按位或|、邏輯與&&、邏輯或||,等等),

接下來是條件運(yùn)算符(?:其實(shí)這是一個(gè)三目運(yùn)算符),

賦值運(yùn)算符(=,/=,*=等等),

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

?

我們需要記住的最重要的一點(diǎn)是:

算術(shù)運(yùn)算符(加減乘除)>

移位運(yùn)算符(左移>>、右移<<) >

關(guān)系運(yùn)算符(大于>、小于<、等于==,等等) >

邏輯運(yùn)算符(按位與&、按位或|、邏輯與&&、邏輯或||,等等)

?

?

轉(zhuǎn)載于:https://www.cnblogs.com/dyllove98/p/3199076.html

總結(jié)

以上是生活随笔為你收集整理的C陷阱与缺陷代码分析之第2章语法陷阱的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。