在一个 表达式 中可能包含多个有不同 运算符 连接起来的、具有不同 数据类型 数据对象 ;由于表达式有多种运算,不同的结合顺序可能得出不同结果甚至出现错误运算错误,因为当表达式中含多种运算时,必须按一定顺序进行结合,才能保证运算的 合理性 和结果的正确性、 唯一性
优先级 从上到下依次递减,最上面具有最高的优先级,逗号 操作符 具有最低的优先级。表达式的结合次序取决于表达式中各种运算符的优先级。优先级高的运算符先结合,优先级低的运算符后结合,同一行中的运算符的优先级相同。
每种同类型的运算符都有内部的运算符优先级,不同类型的运算符之间也有相应的优先级顺序。一个表达式中既可以包括相同类型的运算符,也可以包括不同类型的运算符或者函数。当多种运算符出现在同一个表达式中时,应该先按照不同 类型运算符 间的优先级进行运算。各种运算符间的优先级如下:数值运算符、 字符串运算符 、关系运算符、 逻辑运算符 。可以用括号改变优先级顺序,使得括号内的运算优先于括号外的运算。对于多重括号,总是由内到外强制表达式的某些部分优先运行。括号内的运算总是最优先计算。
优先级
优先级与 求值顺序 无关。如a+b && b*c,虽然*优先级最高,但这个表达式求值顺序是从左到右。
优先级从上到下依次递减,最上面具有最高的优先级,逗号 操作符 具有最低的优先级。
相同优先级中,按 结合性 进行结合。大多数运算符结合性是从左到右,只有三个优先级是从右至左结合的,它们是 单目运算符 条件运算符 赋值运算符
基本的优先级需要记住:
指针最优, 单目运算 优于 双目运算 。如 正负号
算术运算 ,后移位运算,最后位运算。请特别注意:1
逻辑运算 最后结合。
运算符
运算符是一种特殊的函数,它们具有一个或多个 操作数 并返回相应的值。操作数是被运算符用作输入的值,通常是字面值、变量或表达式。运算符可以是一元、二元或三元的, 一元运算符 有1个操作数,二元运算符有2个操作数, 三元运算符 有3个操作数。
结合性
当一个运算对象两侧的运算符优先级别相同时,则按运算符的结合性来确定表达式的 运算顺序 。关于结合性的概念在其他 高级语言 中是没有的,这是 C语言 的特点之一。在标准C语言的文档里,对操作符的结合性并没有做出非常清楚的解释。一个满分的回答是:它是仲裁者,在几个操作符具有相同的优先级时决定先执行哪一个。C语言也将34种运算符规定了不同的结合性。大多数运算符结合方向是“自左至右”,即:先左后右,也叫“左结合性”,例如 a-b + c,表达式中有-和+两种运算符,且优先级相同,按先左后右结合方向,先围绕 减号 结合,执行a-b的运算,再围绕加号结合,完成运算(a-b) + c。除了左结合性外,C 语言有三类运算符的结合方向是从右至左,也叫“右结合性”,即:单目运算符、条件运算符、以及赋值运算符。着重强调一点,无论是左结合性,还是右结合性,是针对两个相邻的优先级相同的运行符而言(不是表达中的运算对象),运算符是决定左右的 基准点 ,先以前面的运算符(即位置上处于左边的运算符)构造运算,就是左结合,反之,就是右结合
优先级
运算符
名称或含义
使用形式
结合方向
说明
1
[]
数组下标
数组名[常量表达式]
左到右
-----
()
圆括号
(表达式)/函数名(形参表)
-----
.
成员选择(对象)
对象.成员名
-----
->
成员选择(指针)
对象指针->成员名
-----
2
-
负号运算符
-表达式
右到左
单目运算符
(类型)
强制类型转换
(数据类型)表达式
-----
++
前置自增运算符
++变量名
单目运算符
++
后置自增运算符
变量名++
单目运算符
--
前置自减运算符
--变量名
单目运算符
--
后置自减运算符
变量名--
单目运算符
*
取值运算符
*指针变量
单目运算符
&
取地址运算符
&变量名
单目运算符
!
逻辑非运算符
!表达式
单目运算符
~
按位取反运算符
~表达式
单目运算符
sizeof
长度运算符
sizeof(表达式)
-----
3
/
表达式/表达式
左到右
双目运算符
*
表达式*表达式
双目运算符
%
余数(取模)
整型表达式/整型表达式
双目运算符
4
+
表达式+表达式
左到右
双目运算符
-
表达式-表达式
双目运算符
5
<<
左移
变量
左到右
双目运算符
>>
右移
变量>>表达式
双目运算符
6
>
大于
表达式>表达式
左到右
双目运算符
>=
大于等于
表达式>=表达式
双目运算符
<
小于
表达式
双目运算符
<=
小于等于
表达式
双目运算符
7
==
等于
表达式==表达式
左到右
双目运算符
!=
不等于
表达式!= 表达式
双目运算符
8
&
按位与
表达式&表达式
左到右
双目运算符
9
^
按位异或
表达式^表达式
左到右
双目运算符
10
|
按位或
表达式|表达式
左到右
双目运算符
11
&&
逻辑与
表达式&&表达式
左到右
双目运算符
12
||
逻辑或
表达式||表达式
左到右
双目运算符
13
?:
条件运算符
表达式1? 表达式2: 表达式3
右到左
三目运算符
14
=
赋值运算符
变量=表达式
右到左
-----
/=
除后赋值
变量/=表达式
-----
*=
乘后赋值
变量*=表达式
-----
%=
取模后赋值
变量%=表达式
-----
+=
加后赋值
变量+=表达式
-----
-=
减后赋值
变量-=表达式
-----
<<=
左移后赋值
变量
-----
>>=
右移后赋值
变量>>=表达式
-----
&=
按位与后赋值
变量&=表达式
-----
^=
按位异或后赋值
变量^=表达式
-----
|=
按位或后赋值
变量|=表达式
-----
15
,
逗号运算符
表达式,表达式,…
左到右
从左向右顺序运算
说明:
同一优先级 的运算符, 运算次序 由结合方向所决定。
简单记就是:! > 算术运算符 > 关系运算符 > && > || > 赋值运算符
运算符
描述
例子
可重载性
第一级别
-----
-----
-----
::
作用域解析符
Class::age = 2;
不可重载
第二级别
-----
-----
-----
()
函数调用
isdigit('1')
可重载
()
成员初始化
c_tor(int x, int y) : _x(x), _y(y*10){};
可重载
[]
数组数据获取
array[4] = 2;
可重载
->
指针型成员调用
ptr->age = 34;
可重载
.
对象型成员调用
obj.age = 34;
不可重载
++
后自增运算符
for( int i = 0; i < 10; i++ ) cout
可重载
--
后自减运算符
for( int i = 10; i > 0; i-- ) cout
可重载
const_cast
特殊属性转换
const_cast(type_from);
不可重载
dynamic_cast
特殊属性转换
dynamic_cast(type_from);
不可重载
static_cast
特殊属性转换
static_cast(type_from);
不可重载
reinterpret_cast
特殊属性转换
reinterpret_cast(type_from);
不可重载
typeid
对象类型符
cout « typeid(var).name();
cout « typeid(type).name();
不可重载
第三级别 (具有右结合性)
-----
-----
-----
!
逻辑取反
if( !done ) …
可重载
not
! 的另一种表达
-----
-----
~
按位取反
flags = ~flags;
可重载
compl
~的另一种表达
-----
-----
++
预自增运算符
for( i = 0; i < 10; ++i ) cout
可重载
--
预自减运算符
for( i = 10; i > 0; --i ) cout
可重载
-
负号
int i = -1;
可重载
+
正号
int i = +1;
可重载
*
指针取值
int data = *intPtr;
可重载
&
值取指针
int *intPtr = &data;
可重载
new
动态元素内存分配
long *pVar = new long;
MyClass *ptr = new MyClass(args);
可重载
new []
动态数组内存分配
long *array = new long[n];
可重载
delete
动态析构元素内存
delete pVar;
可重载
delete []
动态析构数组内存
delete [] array;
可重载
(type)
强制类型转换
int i = (int) floatNum;
可重载
sizeof
返回类型内存
int size = sizeof floatNum;
int size = sizeof(float);
不可重载
第四级别
-----
-----
-----
->*
类指针成员引用
ptr->*var = 24;
可重载
.*
类对象成员引用
obj.*var = 24;
不可重载
第五级别
-----
-----
-----
*
乘法
int i = 2 * 4;
可重载
/
除法
float f = 10.0 / 3.0;
可重载
%
取余数(模运算)
int rem = 4 % 3;
可重载
第六级别
-----
-----
-----
+
加法
int i = 2 + 3;
可重载
-
减法
int i = 5 - 1;
可重载
第七级别
-----
-----
-----
<<
位左移
int flags = 33
可重载
>>
位右移
int flags = 33 >> 1;
可重载
第八级别
-----
-----
-----
<
小于
if( i < 42 ) …
可重载
<=
小于等于
if( i
可重载
>
大于
if( i > 42 ) …
可重载
>=
大于等于
if( i >= 42 ) ...
可重载
第九级别
-----
-----
-----
==
恒等于
if( i == 42 ) ...
可重载
eq
== 的另一种表达
-----
-----
!=
不等于
if( i != 42 ) …
可重载
not_eq
!=的另一种表达
-----
-----
第十级别
-----
-----
-----
&
位且运算
flags = flags & 42;
可重载
bitand
&的另一种表达
-----
-----
第十一级别
-----
-----
-----
^
位异或运算
flags = flags ^ 42;
可重载
xor
^的另一种表达
-----
-----
第十二级别
-----
-----
-----
|
位或运算
flags = flags | 42;
可重载
bitor
|的另一种表达
-----
-----
第十三级别
-----
-----
-----
&&
逻辑且运算
if( conditionA && conditionB ) …
可重载
and
&&的另一种表达
-----
-----
第十四级别
-----
-----
-----
||
逻辑或运算
if( conditionA || conditionB ) ...
可重载
or
||的另一种表达
-----
-----
第十五级别 (具有右结合性)
-----
-----
-----
? :
条件运算符
int i = (a > b) ? a : b;
不可重载
第十六级别 (具有右结合性)
-----
-----
-----
=
赋值
int a = b;
可重载
+=
加赋值运算
a += 3;
可重载
-=
减赋值运算
b -= 4;
可重载
*=
乘赋值运算
a *= 5;
可重载
/=
除赋值运算
a /= 2;
可重载
%=
模赋值运算
a %= 3;
可重载
&=
位且赋值运算
flags &= new_flags;
可重载
and_eq
&= 的另一种表达
-----
-----
^=
位异或赋值运算
flags ^= new_flags;
可重载
xor_eq
^=的另一种表达
-----
-----
|=
位或赋值运算
flags |= new_flags;
可重载
or_eq
|=的另一种表达
-----
-----
<<=
位左移赋值运算
flags <<=2;
可重载
>>=
位右移赋值运算
flags >>= 2;
可重载
第十七级别
-----
-----
-----
throw
异常抛出
throw EClass(“Message”);
不可重载
第十八级别
-----
-----
-----
,
逗号分隔符
for( i = 0, j = 0; i < 10; i++, j++ ) …
可重载
运算符
结合性
[ ] . ( ) (方法调用)
从左向右
! ~ ++ -- +(一元运算) -(一元运算)
从右向左
* / %
从左向右
+ -
从左向右
> >>>
从左向右
< >= instanceof
从左向右
== !=
从左向右
&
从左向右
^
从左向右
|
从左向右
&&
从左向右
||
从左向右
?:
从右向左
=
从右向左
一个特殊的例子:
public class stlye
{
public static void main(String[] args)
{
int a=10,b=6;
System.out.println("改变之前的数:a="+a+",b="+b);
a-=b++;
System.out.println("改变之后的数:a="+a+",b="+b);
}
}
运算结果为:
改变之前的数:a=10,b=6
改变之后的数:a=4,b=7
因为b++运算中先执行++,再返回后置++运算 表达式 (b++)的 返回值 (6)给-=运算符。
在这个程序中a-=b++等于a=a-b++=10-6,所以a=4。
优先级
类别
运算符
1
基本
(x) x.y f(x) a[x] x++ x-- new typeof sizeof checked unchecked
2
单目
+ - ! ~ ++x --x (T)x
3
乘法与除法
* / %
4
加法与减法
+ -
5
移位运算
>
6
关系运算
< > =
7
条件等
== !=
8
位逻辑与
&
9
位逻辑异或
^
10
位逻辑或
|
11
条件与
&&
12
条件或
13
条件
?:
14
赋值
=
一个特殊的例子:
class Program
{
static void Main( string [] args)
{
int a; a = 10; int b = 4;
a += b++;
Console. WriteLine ("a={0}",a);
Console.WriteLine("b={0}", b);
Console. ReadLine ();
}
}
运算结果为:
a=14
b=5
在这个程序中a+=b等于a=a+b=10+4,因为 b++ 时返回了一个临时变量后才进行自增。