8. C语言之操作符详解

07-16 881阅读

文章目录

    • 一、算术操作符
    • 二、移位操作符
      • 1、 原码、反码、补码
      • 2、左移操作符
      • 3、右移操作符
      • 三、位操作符
        • 1、按位与【&】
        • 2、按位或【|】
        • 3、按位异或【^】
        • 4、按位取反【~】
        • 5、两道面试题
        • 6、进制定位
          • 将变量a的第n位置为1
          • 将变量a的第n位置为0
          • 四、赋值操作符
            • 1、复合赋值符
            • 五、单目操作符
              • 1、单目操作符介绍
              • 2、【!】逻辑反操作
              • 3、【&】和【*】
              • 4、【-】和【+】
              • 5、sizeof
              • 6、【++】和【- -】
              • 7、强制类型转换
              • 六、关系操作符
              • 七、逻辑操作符
                  • 一道笔试题~~
                  • 八、条件操作符
                  • 九、逗号表达式
                  • 十、下标引用、函数调用和结构成员
                    • 1、下标引用操作符 [ ]
                    • 2、函数调用操作符 ( )
                    • 3、结构成员调用操作符 . 和 ->
                    • 十一、表达式求值
                      • 1、隐式类型转换【整型提升】
                        • 整型提升的意义
                        • 2、算术转换
                        • 3、操作符的属性【附优先级列表】
                        • 4、问题表达式
                          • 问题表达式1
                          • 问题表达式2
                          • 问题表达式3
                          • 问题表达式4
                          • ⑤ 问题表达式5

                            一、算术操作符

                            8. C语言之操作符详解

                            • 除了 【%】 操作符之外,其他的几个操作符可以作用于整数和浮点数。

                            • 对于【/】 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。

                            • 【%】 操作符的两个操作数必须为整数。返回的是整除之后的余数。

                            • 整数除法:

                              8. C语言之操作符详解

                              • 浮点数除法:

                                8. C语言之操作符详解

                                • 取余操作符

                                  8. C语言之操作符详解

                                  二、移位操作符

                                  8. C语言之操作符详解

                                  1、 原码、反码、补码

                                  • 其实我们经常能听到2进制、8进制、10进制、16进制这样的讲法,那是什么意思呢?其实2进制、8进制、10进制、16进制是数值的不同表示形式而已。
                                  • 比如:数值15的各种进制的表示形式:
                                    15的2进制:1111
                                    15的8进制:17
                                    15的10进制:15
                                    15的16进制:F
                                    
                                    • 对于一个整数来说,在内存中的二进制表示形式有 【原码】【反码】【补码】 三种,写成二进制位的形式也就是32位二进制,例如整数4,它的原码即为0 0000000000000000000000000000100。最高位对于32个二进制位来说,叫做符号位

                                      • 符号位是0,表示正整数
                                      • 符号位是1,表示负整数
                                      • 而对于一个正数来说,它的原码、反码、补码都是相同的

                                      • 对于一个负数来说:

                                        • 原码:直接将数值按照正负数的形式翻译成二进制得到的就是原码。
                                        • 反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。
                                        • 补码:反码+1就得到补码。
                                          • 对于整形来说:数据存放内存中其实存放的是补码。
                                          • 为什么呢?

                                            在计算机系统中,数值⼀律⽤补码来表⽰和存储。原因在于,使⽤补码,可以将符号位和数值域统⼀处理;同时,加法和减法也可以统⼀处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。


                                            • 在计算机中都是使用二进制数的补码进行运算的,但是在计算完之后输出的结果都要再转化为原码的形式

                                              2、左移操作符

                                              【移位规则】:左边抛弃、右边补0

                                              • 下面计算一个数字4左移1位后的,将其运算后的结果放到b里面去。
                                              • 在内存中进行计算都是使用补码的形式,因为依次写出4的原、反、补码,因为它是正数,所以均是相同的
                                                int main()
                                                {
                                                	int a = 4;
                                                	//0 0000000000000000000000000000100 - 4的原码
                                                	//0 0000000000000000000000000000100 - 4的反码
                                                	//0 0000000000000000000000000000100 - 4的补码
                                                	int b = a 
                                                	int a = -4;
                                                	//1 0000000000000000000000000000100 - -4的原码
                                                	//1 1111111111111111111111111111011 - -4的反码
                                                	//1 1111111111111111111111111111100 - -4的补码
                                                	int b = a -1;//error
                                                

                                                三、位操作符

                                                1、按位与【&】

                                                • 【规则】:全1为1,有0为0
                                                  //按位与 - 全1为1,有0为0
                                                  int main()
                                                  {
                                                  	int a = 3;
                                                  	int b = -5;
                                                  	int c = a & b;
                                                  	printf("c = %d\n", c);
                                                  	//00000000000000000000000000000011 - 3的原码、反码、补码
                                                  	//10000000000000000000000000000101 - -5的原码
                                                  	//11111111111111111111111111111010 - -5的反码
                                                  	//11111111111111111111111111111011 - -5的补码
                                                  	//00000000000000000000000000000011
                                                  	//11111111111111111111111111111011
                                                  	//00000000000000000000000000000011 - 3【补码即为原码】
                                                  	return 0;
                                                  }
                                                  
                                                  • 根据按位与的运算规则,我们就可以得出最后的结果为3

                                                    8. C语言之操作符详解

                                                    2、按位或【|】

                                                    • 【规则】:有1为1,全0为0
                                                      //按位或 - 有1为1,全0为0
                                                      int main()
                                                      {
                                                      	int a = 3;
                                                      	int b = -5;
                                                      	int c = a | b;
                                                      	printf("c = %d\n", c);
                                                      	//00000000000000000000000000000011 - 3的原码、反码、补码
                                                      	//10000000000000000000000000000101 - -5的原码
                                                      	//11111111111111111111111111111010 - -5的反码
                                                      	//11111111111111111111111111111011 - -5的补码
                                                      	//00000000000000000000000000000011
                                                      	//11111111111111111111111111111011
                                                      // --------------------------------------
                                                      	//11111111111111111111111111111011 |
                                                      	//11111111111111111111111111111010 |
                                                      	//10000000000000000000000000000101 | - 5
                                                      	return 0;
                                                      }
                                                      
                                                      • 根据按位或的运算规则,我们就可以得出最后的结果为-5

                                                        8. C语言之操作符详解

                                                        3、按位异或【^】

                                                        • 【规则】:相同为0,相异为1
                                                          //按位异或 - 相同为0,相异为1
                                                          int main()
                                                          {
                                                          	int a = 3;
                                                          	int b = -5;
                                                          	int c = a ^ b;
                                                          	printf("c = %d\n", c);
                                                          	//00000000000000000000000000000011 - 3的原码、反码、补码
                                                          	//10000000000000000000000000000101 - -5的原码
                                                          	//11111111111111111111111111111010 - -5的反码
                                                          	//11111111111111111111111111111011 - -5的补码
                                                          	//00000000000000000000000000000011
                                                          	//11111111111111111111111111111011
                                                          // --------------------------------------
                                                          	//11111111111111111111111111111000
                                                          	//11111111111111111111111111110111
                                                          	//10000000000000000000000000001000 -> -8
                                                          	return 0;
                                                          }
                                                          
                                                          • 根据按位异或的运算规则,我们就可以得出最后的结果为-8

                                                            8. C语言之操作符详解

                                                            注意:

                                                            • 两个相同的数异或为0【a ^ a = 0】
                                                            • 任何数和0异或均为那个数本身【a ^ 0 = a】

                                                              4、按位取反【~】

                                                              【规则】:1变0, 0变1

                                                              • 取反直接就可以将1变成0,0变成1
                                                                int main()
                                                                {
                                                                	int a = 0;
                                                                	int b = ~a;
                                                                	printf("b = %d\n", b);
                                                                	//00000000000000000000000000000000
                                                                	//11111111111111111111111111111111  按位取反【补码】	
                                                                	//11111111111111111111111111111110	【反码】
                                                                	//10000000000000000000000000000001 -> -1【原码】
                                                                	return 0;
                                                                }
                                                                
                                                                • 那么0按位取反之后就变成了-1

                                                                  8. C语言之操作符详解

                                                                  5、两道面试题

                                                                  两数交换

                                                                  • 我们之前学的是使用第三方临时变量做一个存放,进行交换

                                                                  • 还有以一种方法就是通过加减的方式来交换一下这两个数

                                                                    int main()
                                                                    {
                                                                    	int a = 3;
                                                                    	int b = 5;
                                                                    	printf("a = %d, b = %d\n", a, b);
                                                                    	a = a + b;
                                                                    	b = a - b;	
                                                                    	a = a - b;		
                                                                    	printf("a = %d, b = %d\n", a, b);
                                                                    	return 0;
                                                                    }
                                                                    
                                                                    • 首先将两个数相加放到a中,再将a-b的值放到b中,此时a中右a和b的值,b中有a的值,最后再将a-b就是b的值

                                                                      8. C语言之操作符详解

                                                                      • 上面这种方法有一点不太好,就是当两个很大的数的时候,会出现数据溢出的情况,所以我们还需要另外一种方法:使用异或
                                                                        • 首先a = a ^ b将a和b异或后的结果暂存到a里面去,然后再去异或b的话就相当于是a ^ b ^ b,根据规则便可以得出结果为a,将其放入b中
                                                                        • 然后a = a ^ b,就相当于是a ^ b ^ a,那么结果就是b,将其放入a中
                                                                          int main()
                                                                          {
                                                                          	int a = 3;
                                                                          	int b = 5;
                                                                          	printf("a = %d, b = %d\n", a, b);
                                                                          	a = a ^ b;
                                                                          	b = a ^ b;		//a ^ b ^ b = a ^ 0 = a
                                                                          	a = a ^ b;		//a ^ b ^ a = b ^ 0 = b
                                                                          	printf("a = %d, b = %d\n", a, b);
                                                                          	return 0;
                                                                          }
                                                                          
                                                                          • 最后打印出来就是交换之后的结果

                                                                            8. C语言之操作符详解

                                                                            6、进制定位

                                                                            将变量a的第n位置为1

                                                                            思路分析:

                                                                            • 首先就是要使用到我们上面学习过的按位或 | 运算,将第三位按位或上一个1,那么这一位就变成了1,但是又不想让其他位置发生变化,那此时就让其他位按位或上一个0即可,若是那个位上为0,那么就是0,若是那个位上为1,那也为1,那也就是00000000000000000000000000000100,但是要如何去获取到这个二进制数呢,此时就又需要使用到我们上面讲到过的一个操作符叫做左移 int a = 10; int n = 0; scanf("%d", &n); a = a | 1 int a = 10; int n = 0; while (scanf("%d", &n)!=EOF) { a = a | 1 int flag = 0; if (!flag) { printf("haha\n"); } return 0; } short s = 10; int a = 2; printf("%d\n", sizeof(s = a + 2)); printf("%d\n", s); return 0; } printf("%d\n", sizeof(arr)); } void test2(char ch[]) { printf("%d\n", sizeof(ch)); } int main() { int arr[10] = {0}; char ch[10] = {0}; printf("%d\n", sizeof(arr)); printf("%d\n", sizeof(ch)); test1(arr); test2(ch); return 0; } int i = 0, a = 0, b = 2, c = 3, d = 4; i = a++ && ++b && d++; printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d); printf("------\n"); printf("i = %d\n", i); return 0; } int a = 5; int b = 0; if (5 == a) b = 3; else b = -3; printf("a = %d\n", a); printf("b = %d\n", b); return 0; } //业务处理 a = get_val(); count_val(a); } //业务处理 } int arr[] = { 1,2,3,4,5 }; int sz = sizeof(arr) / sizeof(arr[0]); for (int i = 0; i price);
                                                                              • 可以看到对于这三种形式都是可以访问到这个结构体变量的成员

                                                                                8. C语言之操作符详解

                                                                                十一、表达式求值

                                                                                1、隐式类型转换【整型提升】

                                                                                • C的整型算术运算总是至少以缺省整型类型的精度来进行的

                                                                                  为了获得这个精度,表达式中的字符型和短整型操作数在使用之前被转换为普通整型,这种转换称为[整型提升]

                                                                                  整型提升的意义
                                                                                  • 表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
                                                                                  • 因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。
                                                                                  • 通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算

                                                                                    如何进行整型提升

                                                                                    • 整形提升是按照变量的数据类型的符号位来提升的

                                                                                      正数的整形提升

                                                                                      char c1 = 1;
                                                                                      
                                                                                      • 正数的原反补码是相同的
                                                                                      • 再将一个整数1赋值给一个char类型的变量c1,此时就会发生截断,字符类型在内存中只占一个字节(8个比特)
                                                                                      • 接下来c1会进行整形提升,在会提升成00000000000000000000000000000001达到整型4个字节32个比特位在内存中的要求

                                                                                        负数的整型提升

                                                                                        char c2 = -1;
                                                                                        
                                                                                        • 负数在内存中存放的是11111111111111111111111111111111,将其给到一个整型的变量之后就会发生截断即为11111111

                                                                                        • 那这个时候再进行一个整型提升就和正数不一样了,因为负数的符号位为1,而整型提升在高位是要补充符号位,所以会在前头加上24个1,那其实也就变回了和之前-1的补码一般的样子,为32个1

                                                                                          2、算术转换

                                                                                          • 如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行

                                                                                            8. C语言之操作符详解

                                                                                            • 如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算。【排名从上面最高,下面最低】
                                                                                            • 例如int和unsigned int一起进行算术运算的时候这个前者就要转换为后者的类型
                                                                                            • 例如long int和long double一起进行算术运算的时候这个前者就要转换为后者的类型
                                                                                            • 那其实可以看出,在char和short面前称霸的int如今沦落为了小弟

                                                                                              【注意】:

                                                                                              但是算术转换要合理,要不然会有一些潜在的问题

                                                                                              int main()
                                                                                              {
                                                                                              	float f = 3.14;
                                                                                              	int num = f;//隐式转换,会有精度丢失
                                                                                              	printf("%d\n", num);
                                                                                              	return 0;
                                                                                              }
                                                                                              

                                                                                              8. C语言之操作符详解

                                                                                              3、操作符的属性【附优先级列表】

                                                                                              复杂表达式的求值有三个影响的因素

                                                                                              1. 操作符的优先级
                                                                                              2. 操作符的结合性
                                                                                              3. 是否控制求值顺序
                                                                                              • 两个相邻的操作符先执行哪个?取决于他们的优先级。如果两者的优先级相同,取决于他们的结合性

                                                                                                下面有一张关于操作符优先级的列表~~

                                                                                                8. C语言之操作符详解

                                                                                                4、问题表达式

                                                                                                表达式的求值部分由操作符的优先级决定,优先级只能决定先算谁,但是哪个表达式先调用要取决于编译器

                                                                                                • 对于有些表达式而言,其实在不同的编译器上所呈现的结果是不同的,我们将其称作为【问题表达式】
                                                                                                  问题表达式1
                                                                                                  a*b + c*d + e*f
                                                                                                  
                                                                                                  • 来看上面这段代码,通过上面的优先级列表可以看出[*]的优先级一定是比[+]要来得高,因此可以保证[*]两端的数字先进行运算,但是却不能保证第三个*比第一个+早执行
                                                                                                    问题表达式2
                                                                                                    • 继续来看下一个问题表达式
                                                                                                      //表达式2
                                                                                                      c + --c;
                                                                                                      12
                                                                                                      
                                                                                                      • 虽然对于这个[--]操作符来说比[+]操作符的优先级来得高,但是呢我们却不知道在编译器运算的时候这个【c】是什么时候准备好
                                                                                                        问题表达式3
                                                                                                        • 对于下面这段代码,也是存在很大的争议,特别是对于++和--混搭的这种表达式尤其严重,你可以去不同的编译器上运行看看,结果都是不一样的~~
                                                                                                          //代码3-非法表达式
                                                                                                          int main()
                                                                                                          {
                                                                                                          	int i = 10;
                                                                                                          	i = i-- - --i * ( i = -3 ) * i++ + ++i;
                                                                                                          	printf("i = %d\n", i);
                                                                                                          	return 0;
                                                                                                          }
                                                                                                          
                                                                                                          • 下面是在不同的编译器上运行出来的结果,可见这个表达式问题有多大!!!
                                                                                                            编译器
                                                                                                            - 128Tandy 6000 Xenix 3.2
                                                                                                            - 95Think C 5.02(Macintosh)
                                                                                                            - 86IBM PowerPC AIX 3.2.5
                                                                                                            - 85Sun Sparc cc(K&C编译器)
                                                                                                            - 63gcc,HP_UX 9.0,Power C 2.0.0
                                                                                                            4Sun Sparc acc(K&C编译器)
                                                                                                            21Turbo C/C++ 4.5
                                                                                                            22FreeBSD 2.1 R
                                                                                                            30Dec Alpha OSF1 2.0
                                                                                                            36TDec VAX/VMS
                                                                                                            42Microsoft C 5.1

                                                                                                            问题表达式4
                                                                                                            • 看到main函数中的函数调用表达式answer = fun() - fun() * fun();其实也是存在一个歧义的,因为你完全不知道编译器先调用的是哪个fun()
                                                                                                              //代码4
                                                                                                              int fun()
                                                                                                              {
                                                                                                                   static int count = 1;
                                                                                                                   return ++count;
                                                                                                              }
                                                                                                              int main()
                                                                                                              {
                                                                                                                   int answer;
                                                                                                                   answer = fun() - fun() * fun();
                                                                                                                   printf( "%d\n", answer);//输出多少?
                                                                                                                   return 0;
                                                                                                              }
                                                                                                              
                                                                                                              • 可以看到,若是前面的fun()先执行的话,最后的结果就是-10,若是后面的fun()先执行的话,最后的结果就是-2

                                                                                                              • 正常来说大家应该都认为是第二个表达式符合我们的运算规则,因为先乘除后加减,可是呢我们最常用的VS出来的结果都不是我们想要的

                                                                                                                我们可以到不同编译器上面去观察一下

                                                                                                                8. C语言之操作符详解

                                                                                                                • 可以看到,虽然在【VS】和【Linux】在执行的结果是-10,而且在大多数的编译器下都是这个,但是呢对于函数的调用先后顺序无法通过操作符的优先级确定,因此这也是一个问题表达式

                                                                                                                  8. C语言之操作符详解


                                                                                                                  ⑤ 问题表达式5
                                                                                                                  • 有关++和+结合的问题表达式
                                                                                                                    //代码5
                                                                                                                    #include 
                                                                                                                    int main()
                                                                                                                    {
                                                                                                                    	int i = 1;
                                                                                                                    	int ret = (++i) + (++i) + (++i);
                                                                                                                    	printf("%d\n", ret);
                                                                                                                    	printf("%d\n", i);
                                                                                                                    	return 0;
                                                                                                                    }
                                                                                                                    

                                                                                                                    8. C语言之操作符详解

                                                                                                                    • 可以看到,这里就出现了两个不同的结果,VS里运行出来是【12】,在linux里面运行出来是【10】

                                                                                                                      8. C语言之操作符详解

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]