函數聲明和運算符優先級詳解

1、函數聲明

對於

<span style="font-size:18px;">(* (void(*) () 0));這樣的函數,怎樣理解呢?</span>

       首先,我們都知道任何C變量的聲明都由兩部分組成:類型以及一組類似表達式的聲明符。聲明符從表面上看與表達式有些類似,對它求值應該返回一個聲明中給定類型的結果。

最簡單的聲明符就是單個變量,例如:

<span style="font-size:18px;"><span style="font-size:18px;">float f, g;</span></span>
這個聲明的含義是:當對其求值時,表達式f和g的類型爲浮點型。因爲聲明符與表達式相似,所以我們也可以在聲明符中任意使用括號,例如

<span style="font-size:18px;">float ((f));</span>
意義同上。

同樣的邏輯也適用於函數和指針類型的聲明。例如:

<span style="font-size:18px;">float ff();</span>
這個聲明的含義是:表達式ff()求值結果時一個浮點數,即ff是一個返回值爲浮點類型的函數。類似的,還有,

<span style="font-size:18px;">float *pf;</span>
這個聲明的含義是:*pf是一個浮點數,即pf是一個指向浮點數的指針。

對於如下的:

<span style="font-size:18px;">float *g(), (*h)();</span>
表示*g()和(*h)()是浮點數表達式。因爲()結合優先級高於*,*g()也就是*(g()):g是一個函數,該函數的返回值類型爲指向浮點數的指針。對於(*h)(),h是一個函數指針,h所指向函數的返回值爲浮點類型。

一旦我們知道了如何聲明一個給定類型的變量,那麼該類型的類型轉換符就很容易得到了:只要把聲明中變量名和聲明末尾的分號去掉,再將剩餘的部分用一個括號整個“封裝”起來即可。例如:

<span style="font-size:18px;">float (*h)();</span>
<span style="font-size:18px;">(float (*) () )</span>
它表示一個“指向返回值爲浮點類型的函數指針”的類型轉換符。

現在來解釋

<span style="font-size:18px;">(* (void)(*)() 0)()</span>
對於這個表達式,分兩步解釋:

第一步:假定變量fp是一個函數指針,那麼如何調用fp所指向的函數呢?

調用方法如下:

<span style="font-size:18px;">(*fp) ();</span>
因爲fp一個函數指針,那麼*fp就是該指針所指向的函數,所以(*fp)()就是調用該函數的方式。

在上面的表達式中,兩側的括號非常重要,因爲函數運算符()的優先級高於單目運算符*。如果*fp兩側沒有括號,那麼*fp()實際上與*(fp())的含義完全一致。

第二步:找到一個恰當的表達式來替換fp,

對於(*0) ();並不能生效,因爲運算符*必須要一個指針來做操作數。這個指針還應該是一個函數指針,這樣經運算符*作用後的結果才能作爲函數被調用。因此,上式中必須對0做類型轉換,轉換後的類型可以大致描述爲:“指向返回值爲void類型的函數的指針”。

2、運算符優先級

例如:

我們想判斷flag變量與FLAG變量的二進制表示中相同位置的數字是否一樣

<span style="font-size:18px;">if(flag & FLAG)...</span>
上式的含義對大多數C程序員來說是顯而易見的。if語句的判斷括號內表達式的值是否爲0。考慮到可讀性,如果對錶達式的值是否爲0的判斷能夠顯示地加以說明,無疑使得代碼自身就起到了註釋該段代碼意圖的作用。其寫法如下:

<span style="font-size:18px;">if(flag & FLAG != 0)...</span>
但是這是一個錯誤的語句因爲!=運算符的優先級要高於&運算符,所以上式實際上被解釋爲:

<span style="font-size:18px;">if(flag & (FLAG != 0))...</span>

C語言運算符優先級如下

優先級

運算符

實例

結合性

優先級

運算符

實例

結合性

1

()

(a+b)/4;

7

if(i<42)…

[]

array[4]=2;

<=

if(i<=42)…

->

ptr->age=34;

if(i>42)…

.

obj.age=34;

>=

if(i>=42)…

::

Class::age=2;

8

==

if(i==42)…

從左向右

++

for(i=0;i<10;i++)..

!=

if(i!=42)…

--

for(i=0;i<10;i--)…

9

&

flags=flags&42;

從左向右

2

!

if(!done)…

10

^

flags=flags^42;

從左向右

~

flags = ~flags;

11

|

flags=flags|42;

從左向右

++

for(i=0;i<10;++i)…

12

&&

if(a && b)…

從左向右

--

for(i=0;i<10;--i)…

13

||

if(a || b)…

從左向右

-

int i = -1;

14

?:

int i=(a>b)?a:b

從右向左

+

int i = +1;

15

=

int a=b;

*

data = *ptr;

+=

a+=3;

&

address=&obj;

-=

b-=4;

(type)

int i=(int)floatNum;

*=

a*=5;

sizeof

int size=sizeof(floatNum);

/=

a/=2;

3

->*

ptr->*var=24;

從左向右

%=

a%=3;

.*

obj.*var=24;

&=

a&=new_a;

4

*

int i=2*4;

從左向右

^=

a^=new_a;

/

float f=10/3;

|=

a|=new_a;

%

int ren=4%3;

<<=

flag<<=2;

5

+

int i=2+3;

從左向右

>>=

flag>>=2;

-

int i=5-1;

16

,

for(i=0;i<10;i++,j++)

從左向右

6

<< 

int flags=33<<1;

從左向右

>> 

int flags=33>>1;




























注:(1)任何一個邏輯運算符的優先級低於任何一個關係運算符

       (2)移位運算符的優先級比算術運算符要低,但是比關係運算符要高。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章