函数声明和运算符优先级详解

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)移位运算符的优先级比算术运算符要低,但是比关系运算符要高。

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