一、算术操作符:+ - * / %
(1)+,-
+和-既可以作为一元运算符,也可以作为二元运算符。所谓“一元运算符”,指的是只需要一个运算数就可以执行。一元运算符-用来改变一个值的正负号。
int x = -1;
上面示例中,-将1这个值变成-1。
二元运算符+和-用来完成加法和减法。
int x = 4 + 22;
int y = 61 - 23;
(2)*
运算符*用来完成乘法。
int num = 5;
printf ( "%i\n" , num * num) ; // 输出 25
(3)/
运算符/用来完成除法。注意,两个整数相除,得到还是一个整数。
float x = 6 / 4;
printf ( "%f\n" , x) ; // 输出 1.000000
上面示例中,尽管变量x的类型是float(浮点数),但是6 / 4得到的结果是1.0,而不是1.5。原因就在于 C 语言里面的整数除法是整除,只会返回整数部分,丢弃小数部分。
如果希望得到浮点数的结果,两个运算数必须至少有一个浮点数,这C 语言就会进行浮点数除法 。
float x = 6.0 / 4; // 或者写成 6 / 4.0
printf ( "%f\n" , x) ; // 输出 1.500000
上面示例中,6.0 / 4表示进行浮点数除法,得到的结果就是1.5。
下面是另一个例子。
int score = 5;
score = ( score / 20) * 100;
上面的代码,你可能觉得经过运算,score会等于25,但是实际上score等于0。这是因为score / 20是整除,会得到一个整数值0 ,所以乘以100后得到的也是0。
为了得到预想的结果,可以将除数20改成20.0 ,让整除变成浮点数除法。
score = ( score / 20.0) * 100;
(4)%
运算符%表示求模运算,即返回两个整数相除的余值。这个运算符只能用于整数,不能用于浮点数。
int x = 6 % 4; // 2
负数求模的规则是,结果的正负号由第一个运算数的正负号决定。
11 % -5 // 1
-11 % -5 // -1
-11 % 5 // -1
上面示例中,第一个运算数的正负号(11或-11)决定了结果的正负号。
二、移位操作符:>> <<
(1)>>
移动的是二进制位,将左侧运算数的每一位,向左移动指定的位数,尾部空出来的位置使用0填充。
int main()
{
int a = 2; //二进制:0000 0010
int b = a << 1; //左移一位 0000 0100
int c = a << 2; //左移两位 0000 1000
printf ( "%d\n" , b) ;
printf ( "%d\n" , c) ;
return 0;
}
(2)>>
右移运算符>>
将左侧运算数的每一位,向右移动指定的位数,尾部无法容纳的值将丢弃,头部空出来的位置使用0填充。
int main()
{
int a = 18; //二进制:0001 0010
int b = a >> 1; //右移一位 0000 1001
int c = a >> 2; //右移两位 0000 0100
printf ( "%d\n" , b) ;
printf ( "%d\n" , c) ;
return 0;
}
注意,右移运算符最好只用于无符号整数,不要用于负数。因为不同系统对于右移后如何处理负数的符号位,有不同的做法,可能会得到不一样的结果。
三、位操作符:~ & | ^
C 语言提供一些位运算符,用来操作二进制位(bit)。
(1)取反运算符~
取反运算符~
是一个一元运算符,用来将每一个二进制位变成相反值,即0变成1,1变成0。
// 返回 01101100
~ 10010011
上面示例中,~对每个二进制位取反,就得到了一个新的值。
注意,~运算符不会改变变量的值,只是返回一个新的值。
(2)与运算符&
与运算符&将两个值的每一个二进制位进行比较,返回一个新的值。当两个二进制位都为1,就返回1,否则返回0。
// 返回 00010001
10010011 & 00111101
上面示例中,两个八位二进制数进行逐位比较,返回一个新的值。
与运算符&可以与赋值运算符=结合,简写成&=。
int val = 3;
val = val & 0377;
// 简写成
val &= 0377;
(3)或运算符|
或运算符|
将两个值的每一个二进制位进行比较,返回一个新的值。两个二进制位只要有一个为1(包含两个都为1的情况),就返回1,否则返回0。
// 返回 10111111
10010011 | 00111101
或运算符|可以与赋值运算符=结合,简写成|=。
int val = 3;
val = val | 0377;
// 简写为
val |= 0377;
(4)异或运算符^
异或运算符^
将两个值的每一个二进制位进行比较,返回一个新的值。两个二进制位有且仅有一个为1,就返回1,否则返回0。
// 返回 10101110
10010011 ^ 00111101
异或运算符^
可以与赋值运算符=结合,简写成^=
。
int val = 3 ;
val = val ^ 0377 ;
val ^= 0377 ;
四、逻辑操作符
逻辑操作符提供逻辑判断功能,用于构建更复杂的表达式,主要有下面三个操作符。
!:
否运算符(改变单个表达式的真伪)。
if ( ! ( x < 12 ) )
printf ( "x is not less than 12\n" ) ;
上面示例中,由于否运算符!具有比<更高的优先级,所以必须使用括号,才能对表达式x < 12进行否运算。当然,合理的写法是if (x >= 12),这里只是为了举例。
&&:
与运算符(两侧的表达式都为真,则为真,否则为伪)。
if ( x < 10 && y > 20 )
printf ( "Doing something!\n" ) ;
上面示例中,只有x < 10和y > 20同时为真,x < 10 && y > 20才会为真。
||:
或运算符(两侧至少有一个表达式为真,则为真,否则为伪)。
对于逻辑运算符来说,任何非零值都表示真,零值表示伪。比如,5 || 0会返回1,5 && 0会返回0。
逻辑运算符还有一个特点,它总是先对左侧的表达式求值,再对右边的表达式求值,这个顺序是保证的。如果左边的表达式满足逻辑运算符的条件,就不再对右边的表达式求值。这种情况称为“短路”。
if ( number != 0 && 12 / number == 2 )
上面示例中,如果&&左侧的表达式(number != 0)为伪,即number等于0时,右侧的表达式(12/number == 2)是不会执行的。因为这时左侧表达式返回0,整个&&表达式肯定为伪,就直接返回0,不再执行右侧的表达式了。
由于逻辑运算符的执行顺序是先左后右,所以下面的代码是有问题的。
while ( ( x++ < 10 ) && ( x + y < 20 ) )
上面示例中,执行左侧表达式后,变量x的值就已经变了。等到执行右侧表达式的时候,是用新的值在计算,这通常不是原始意图。