源程序中,但凡可以出现某种类型的数据的地方都可以用同类型的表达式替换。一个表达式的类型,取决于多个方面.
操作符有单目操作符和双目操作符, 还有三目操作符(? : 是C语言唯一的一个三目操作符)。"目"指的是操作数的个数! C语言没有指定同一操作符的多个操作数的计算顺序(除了&& || ? : 和,)。所以语句x = f() + g();的计算结果依赖不同的编译器。
逗号操作符,可以连接多个独立的表达式, 最后一个表达式的计算结果将作为逗号操作运算的结果。
自增自减操作符
++是自增操作符,--是自减操作符。他们可以对变量进行操作,可以实现把变量内部的数字加一或者减一。这两个操作符写在变量前面的时候被称为"前缀操作符",写在后面是被称为"后缀操作符"。这两种情况下,其效果都是将变量的值加一或者减一。但是,它们之间有一点不同。作为前缀操作符,会先完成自增或者自减,然后再供其他操作使用,作为后缀操作符,会在完成自增或者自减的同时,提供一个自增自减前的值给其他操作使用。
实际上可以进一步理解后++/后--
int i = 1;
int j = 0;
j = i++;//OK.
i++ = 100;//ERROR.错误:赋值运算的左操作数必须是左值,而表达式i++的计算结果是个右值. (p.s. ++i的计算结果是个左值。)
/*
* 对于表达式i++;编译器将按照如下步骤处理:
* step1:制作一个i的副本(临时的匿名的变量,这里临时记作i_bak.)
* step2:给i增加1
* step3:将i的副本i_bak返回作为表达式i++的计算结果
*
* 结论:(1)C/C++中,基本类型的临时匿名变量是不可更改的。表达式的计算结果是个右值。
* (2)C/C++中,后置++/后置--计算结果导致操作数增加或者减少1。
*/
逻辑运算(逻辑运算是指计算结果只有真假两种结果的运算)操作符:
== > < >= <= !=
逻辑非(!) 逻辑与(&&) 逻辑或(||)
按位求反(~) 按位与AND(&) 按位或OR(|) 按位异或XOR(^)
/*请理解这条语句 3 > 5 && ++num;*/
3 > 5 && ++num;//计算机中逻辑运算(逻辑与和逻辑或)存在短路特性。当已经判定逻辑表达式运算结果,那么不管逻辑表达式是否全部判定结束都停止判定。
printf("num是%d\n", num);//num的打印结果是0
3 < 5 || ++num;//逻辑或的短路特性
printf("num是%d\n", num);//num的打印结果依然是0
对于逻辑运算,要知道C语言中任何数据信息都可以参与逻辑运算。参与的规则:只有零才是假,其他都是真"
位运算。位运算操作符:
按位取反(~)
按位与AND(&)
按位或OR(|)
按位异或XOR(^)
左移<<
右移>>
(特别注意:机器数采用的二进制编码方式是补码,补码参与运算,计算结果依然是补码)
&是按位与,通常可以用按位与运算把某个机器数中特定的位清零。举个例子:判断一个int
integer 的奇偶性可以这样做 (integer & 0x1),这样做的好处是计算速度快。
|是按位或(OR), 通常可以用按位或运算把某个机器数中特定位置为1。
^是按位异或(XOR), 通常可以用按位异或运算把某个机器数特定位求反.举个例子:求一个int integer的相反数可以这样做 (integer ^ 0x11111111) + 1, 这样做的好处是计算速度快。
~是按位求反,按位求反实现了对某个机器数按位求反。
<<是按位左移,左移会给右边补零,左移一位数值扩大一倍。
>>是按位右移,对于无符号类型,右移会给左边补零;对于有符号类型,右移会给左边补符号位;右移一位数值缩小1/2倍
隐式类型转换会把占地小的数据类型转换为占地大的数据类型,如果数据类型占地大小一样则会把有符号的数据类型转换成无符号类型的数据。例如:
/*请理解如下代码*/
int num = -10;
unsigned int num2 = 3;
num = (num + num2) > 0 ? 1 : -1;//隐身类型转换原则:把占有空间小的调整为占有空间大的,如果占有空间一样,则把有符号的数据转换为无符号数据
printf("(num + num2) > 0 ? 1 : -1 是%d\n", num);//num是1
操作符有单目操作符和双目操作符, 还有三目操作符(? : 是C语言唯一的一个三目操作符)。"目"指的是操作数的个数! C语言没有指定同一操作符的多个操作数的计算顺序(除了&& || ? : 和,)。所以语句x = f() + g();的计算结果依赖不同的编译器。
/*
* 文件名: 3mu.c
* 描述:(1)一个表达式的类型取决于多个方面(表达式的操作数类型)
* (2)C语言没有指定同一操作符的多个操作数的计算顺序,
* 除了: 逻辑与(&&) 逻辑或(||) 三目操作符(? : ) 逗号操作符(,)
* 她们的操作数计算顺序是自左而右,当可以得到计算结论时就停止计算,返回计算结果
*
*
* */
#include <stdio.h>
int main()
{
char c = 'a';
double d = 0.0;
printf("c是%c, d是%f\n", c, d);// a, 0.000000
c ? c = 'A' : (d = 10.99); // 三目操作符号的运算从左至右,得出计算结论就不再计算,该行代码会导致c被赋值'A',不会导致d被赋值
//c ? c = 'A' : d = 10.99; //ERROR 赋值操作符号优先级低于三目操作符,三目操作符的表达式运算结果是右值! 也就是说该行语句等价于(c ? c = 'A' : d) = 10.99;
/*编译器gcc报错如下:
* 3mu.c: 在函数‘main’中:
* 3mu.c:9:28: 错误:赋值运算的左操作数必须是左值
* c ? c = 'A' : d = 10.99
* ^
*/
printf("c是%c, d是%f\n", c, d);// A, 0.000000
printf("表达式 c ? c = 'A' : (d = 10.99) 的类型是double, 表达式的值将占有空间 %d Byte\n", sizeof(c ? c = 'A' : (d = 10.99)));//sizeof()操作符计算表达式值占有的空间大小时候会全面考虑表达式所有的操作数
return 0;
}
逗号操作符,可以连接多个独立的表达式, 最后一个表达式的计算结果将作为逗号操作运算的结果。
自增自减操作符
++是自增操作符,--是自减操作符。他们可以对变量进行操作,可以实现把变量内部的数字加一或者减一。这两个操作符写在变量前面的时候被称为"前缀操作符",写在后面是被称为"后缀操作符"。这两种情况下,其效果都是将变量的值加一或者减一。但是,它们之间有一点不同。作为前缀操作符,会先完成自增或者自减,然后再供其他操作使用,作为后缀操作符,会在完成自增或者自减的同时,提供一个自增自减前的值给其他操作使用。
实际上可以进一步理解后++/后--
int i = 1;
int j = 0;
j = i++;//OK.
i++ = 100;//ERROR.错误:赋值运算的左操作数必须是左值,而表达式i++的计算结果是个右值. (p.s. ++i的计算结果是个左值。)
/*
* 对于表达式i++;编译器将按照如下步骤处理:
* step1:制作一个i的副本(临时的匿名的变量,这里临时记作i_bak.)
* step2:给i增加1
* step3:将i的副本i_bak返回作为表达式i++的计算结果
*
* 结论:(1)C/C++中,基本类型的临时匿名变量是不可更改的。表达式的计算结果是个右值。
* (2)C/C++中,后置++/后置--计算结果导致操作数增加或者减少1。
*/
逻辑运算(逻辑运算是指计算结果只有真假两种结果的运算)操作符:
== > < >= <= !=
逻辑非(!) 逻辑与(&&) 逻辑或(||)
按位求反(~) 按位与AND(&) 按位或OR(|) 按位异或XOR(^)
/*请理解这条语句 3 > 5 && ++num;*/
3 > 5 && ++num;//计算机中逻辑运算(逻辑与和逻辑或)存在短路特性。当已经判定逻辑表达式运算结果,那么不管逻辑表达式是否全部判定结束都停止判定。
printf("num是%d\n", num);//num的打印结果是0
3 < 5 || ++num;//逻辑或的短路特性
printf("num是%d\n", num);//num的打印结果依然是0
对于逻辑运算,要知道C语言中任何数据信息都可以参与逻辑运算。参与的规则:只有零才是假,其他都是真"
位运算。位运算操作符:
按位取反(~)
按位与AND(&)
按位或OR(|)
按位异或XOR(^)
左移<<
右移>>
(特别注意:机器数采用的二进制编码方式是补码,补码参与运算,计算结果依然是补码)
&是按位与,通常可以用按位与运算把某个机器数中特定的位清零。举个例子:判断一个int
integer 的奇偶性可以这样做 (integer & 0x1),这样做的好处是计算速度快。
|是按位或(OR), 通常可以用按位或运算把某个机器数中特定位置为1。
^是按位异或(XOR), 通常可以用按位异或运算把某个机器数特定位求反.举个例子:求一个int integer的相反数可以这样做 (integer ^ 0x11111111) + 1, 这样做的好处是计算速度快。
~是按位求反,按位求反实现了对某个机器数按位求反。
<<是按位左移,左移会给右边补零,左移一位数值扩大一倍。
>>是按位右移,对于无符号类型,右移会给左边补零;对于有符号类型,右移会给左边补符号位;右移一位数值缩小1/2倍
/*
* 文件名: swap.c
* 描述:不引入第三个变量,交换两个变量的值
* */
#include <stdio.h>
int main(void)
{
char a = 'A', b = 'B';
printf("a是%c, b是%c\n", a, b);
a = a ^ b;
b = b ^ a;
a = a ^ b;
printf("a是%c, b是%c\n", a, b);
}
C语言中可以使用强制类型转换把任何一种数据类型的数据当成另外一种类型的数据来使用。
隐式类型转换会把占地小的数据类型转换为占地大的数据类型,如果数据类型占地大小一样则会把有符号的数据类型转换成无符号类型的数据。例如:
/*请理解如下代码*/
int num = -10;
unsigned int num2 = 3;
num = (num + num2) > 0 ? 1 : -1;//隐身类型转换原则:把占有空间小的调整为占有空间大的,如果占有空间一样,则把有符号的数据转换为无符号数据
printf("(num + num2) > 0 ? 1 : -1 是%d\n", num);//num是1