C语言基础- *** 作符

C语言基础- *** 作符,第1张

*** 作符 算术 *** 作符
  • +
  • -
  • *
  • /
  • % 浮点型运算不支持取模运算
移位 *** 作符
  • 整数在内存中以补码的方式存在

    • 正数的补码是源码
    • 负数的补码是源码的反码+1
  • >>

    • 算术右移

      • 右边丢弃,左边补原符号位
      • 无符号类型右移右移都是“逻辑移位”
        有符号类型右移为“逻辑移位”右移为“算术移位”
    • 逻辑右移

      • 右边丢弃,左边补0
  • <<

    • 左移

      • 左边丢弃(符号位不变),右边补0
位 *** 作符
  • &

    • 位与运算(按位与)

      • 整型二进制位相同(1和1)则取1,否则取0
  • |

    • 位或运算(按位或)

      • 整型二进制位相同或不同(1和1或1和0或0和1)取1,否则取0

        • -2 | 1

          1000 0000 0000 0000 0000 0000 0000 0010 -2
          1111 1111 1111 1111 1111 1111 1111 1101 -2反码
          1111 1111 1111 1111 1111 1111 1111 1110 -2补码

          0000 0000 0000 0000 0000 0000 0000 0001 1 源码
          1111 1111 1111 1111 1111 1111 1111 1110 -2 补码

          1111 1111 1111 1111 1111 1111 1111 1111 | (补码)
          1000 0000 0000 0000 0000 0000 0000 0001 源码

  • ^

    • 位异或运算(按位异或)

      • 整型二进制位不同(1和0或0和1)取1,否则取0
  • 例题

    • 例题1:不创建临时变量交换a、b两值
  - 解题1  
		 //不创建临时变量交换a、b的值
		   int a = 3;
		   int b = 5;
		   printf("a = %d,b = %d", a, b);
		   a = a + b;
		   b = a - b;
		   a = a - b;
		  
		   printf("a = %d,b = %d",a ,b);
	
 /*--------------------------------------------*/	
  -  解题2(优化解题一) 
			   //不创建临时变量交换a、b的值
		   int a = 3;
		   int b = 5;
		   printf("a = %d,b = %d", a, b);
		   a = a ^ b;
		   b = a ^ b;
		   a = a ^ b;
		  
		   printf("a = %d,b = %d",a ,b);
		  

例题2:求一个整数在内存中1的个数。

- 解题一

		   int num = 0;
		   scanf("%d",&num);
		  
		   int count = 0;
		   while (num){
		   if (num % 2 == 1){
		   count++;
		   }
		   num /= 2;
		   }
		  
		   printf("%d", count);
 /*--------------------------------------------*/			  
 - 解题2(优化解题一)

		   //求一个整数在内存中1的个数。

int num = 0; scanf("%d",&num); int count = 0; for (int i = 0; i < 32; i++){ if (1 == ((num >> i) & 1)){ count++; } } printf("%d", count); /*--------------------------------------------*/ - 解题3(最优) //求数字在内存中1的个数。

int input = 0; int count = 0; scanf("%d",&input); //18 //10010 n //10001 n-1 //10000 n=n&(n-1) //01111 n-1 //00000 n=n&(n-1) //每次n&(n-1)都会将最右边的一个1磨掉。

while (input){ input = input & (input - 1); count++; } printf("%d",count);

例题3:整数在内存中求两个数之间有多少位不同

	- 解题1

		  //整数在内存中求两个数之间有多少位不同
		   int m = 0;
		   int n = 0;
		   scanf("%d %d",&m,&n);
		   int count = 0;
		   int num = m^n;
		  
		   while (num){
		   num = num&(num - 1);
		   count++;
		   }
		  
		   printf("%d",count);
赋值 *** 作符
  • 变量名 = 值
单目 *** 作符
  • 只有一个 *** 作数

    • !

      • 逻辑取反
    • +

    • -

    • &

      • 取地址 *** 作符
    • ++ 自增

      • ++a
      • a++
    • - - 自减

      • \ - -a
      • a- -
    • *

      • 间接访问 *** 作符(解引用)
    • ~

      • 按位取反

        • 例题一:
          //按位取反;
          //将内存中的1011中的0变为1
          int a = 11;
          a = a | (1 << 2);
          printf("%d",a);
          //将a变为原来的1011
          a = a & ~(1 << 2);
          printf("%d", a);
    • (类型)

      • 强制类型转换
    • sizeof

      • 计算变量在内存中所占的字节数

      • sizeof 求数组的类型大小

        • sizeof(int [10]) 其结果为40.

      注意:

				shor s = 0;
				int a = 2;
				printf("%d\n",sizeof((s = a +5)));
				printf("%d",s);


			其结果为2   0; 这是因为sizeof的表达式语句是不参与运算的。

例题

sizeof的结果和负数比较

例题一:

			      //10000000 00000000 00000000 00000001  -1源码
				  //11111111 11111111 11111111 11111110  -1补码
				  //11111111 11111111 11111111 11111111  -1补码
				  //11111111 11111111 11111111 11111111  (符号整型)-1
				  //-1转换为无符号整型,最高位的1不再是符号位,而是数据位
				  
				  	int a = -1;
				  	
				  	if (a > sizeof(a)){
				  		printf(">");
				  	}
				  	if (a < sizeof(a)){
				  		printf("<");
				  	}
				  	
关系 *** 作符
  • >
  • <
  • >=
  • <=
  • !=
  • ==
逻辑 *** 作符
  • &&

    • 逻辑与

      • 左边如果为假,则右边的不再计算。

  • ||

    • 逻辑或

      • 左边如果为真,则右边的不再计算。

条件 *** 作符
  • 又名三目运算
  • exp1 ? exp2 : exp3
逗号表达式
  • exp1 , exp2 , exp3 , …
  • 由左向右依次执行,最后一个表达式内容为整个表达式结果
下标引用、函数调佣和结构成员
  • [] 下标引用 *** 作符
  • () 函数调用 *** 作符
  • " . " 结构体变量名.成员名
  • “->” 结构体指针变量名->成员名
表达式求值
  • 表达式求值的顺序部分是由 *** 作符的优先级和结核性决定的。


    同时,有些表达式的 *** 作数在求值的过程中需要转换成其他数据类型。

  • 隐式类型转换

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

    • 整型提升

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

      • 如何提升

        • 按照数据类型的符号来提升的(除值外,其他值补符号位值)
      • 何时需要整型提升

        • 在进行short/char类型进行算术运算时,先进行整型提升,再进行算术运算。

      • 意义

        • 表达式的整形运算要在CPU的相应运算器件内执行,CPU内整形运算器(ALU)的 *** 作数的字节长度一般就是int的字节长度,同时也是CPU通用寄存器的长度。

        • 因此,即两个char类型相加,在CPU执行时实际上也要先转换CPU内整型 *** 作数的标准长度
        • 通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。

          所以,表达式中各种长度可能小于int长度的整型值,都必须转为int或unsigned int,然后才能送入CPU去执行运算

      • 例题:

        • 例题1
			   //整型提升例题
			   //00000011 -(char类型) a 
			   char a = 3;
			   //01111111
			   char b = 127;
			   // a + b 先将a 和 b转换成int型
			   //00000000 00000000 00000000 00000011  -(int类型) a
			   //00000000 00000000 00000000 01111111  -(int类型) b
			   //00000000 00000000 00000000 10000010  -(int类型) a+b
			   
			   //10000010 -(char类型) c
			   char c = a + b;
			   //以十进制的方式输出字符类型的c。

需要整型提升。

//10000010 因为符号位为1,所以按照符号位填充 //11111111 11111111 11111111 10000010 -(int 类型) c --补码 //11111111 11111111 11111111 10000001 -(int 类型) c --反码 补码-1是反码 反码+1是补码 //10000000 00000000 00000000 01111110 -(int 类型) c --源码 // -126 c printf("%d" , c);

		- 例题2
			   // 10110110  -a
			   //11111111 11111111 11111111 10110110 int a  整形提升(补码)
			   //10000000 00000000 00000000 01001010  a -32694  (源码)
			   char a = 0xb6;
			   //10110110 00000000  -0xb600
			   //00000000 00000000 10110110 00000000   int
			   //10110110 00000000 -short b
			   //11111111 11111111 10110110 00000000 -b 整形提升(补码)
			   //11111111 11111111 10110101 11111111 -b 整形提升(反码)
			   //10000000 00000000 01001010 00000000 -b 源码 
			   short b = 0xb600;
			   //
			   //10110110 00000000 00000000 00000000  -0xb6000000
			  
			   int c = 0xb6000000;
			   
			   //
			   if (a == 0xb6){
			   printf("c");
			   }
			   if (b == 0xb600){
			   printf("b");
			   }
			   if (c == 0xb6000000){
			   printf("c");
			   }
			- (char)((char)127+(char)10)   =   -124
			(int)((char)127+(char)10)   =   132
  • 算数转换

    • long double
      double
      unsigned long int
      long int
      unsigned int
      int
      依次向上转换
*** 作符的属性
  • 复杂表达式的求值有三个影响的因素
  • ①: *** 作符的优先级
  • ②: *** 作符的结核性
  • ③:是否控制求值顺序
  • 两个相邻的 *** 作符限先执行哪个?取决于他们的优先级。


    如果两者的优先级相同,取决于他们的结合性。

    *** 作符优先级。

一些问题表达式
  • ab +cd + e*f

    • 该表达式只能保证的运算比+的运算提前,但不能保证运算顺序唯一
      顺序一:
      a
      b
      cd
      a
      b + cd
      e
      f
      ab + cd + ef
      顺序二:
      a
      b
      cd
      e
      f
      ab + cd + e*f
  • c + --c

    • 该表达式只能保证–c在+运算符之前。

      但并不能保证c的值是–c计算过后还是之前

非法表达式
int main(){
int i = 10;
i = i-- - --i *(i = -3) * i++ + ++i;
}
printf("%d",i);

该表达式在不同的编译器中有不同的结果。

int fun(){
	static int num = 1;
	return ++num;
}
int main(){
	
	int answer;
	answer = fun() - fun() * fun();
	printf("%d",answer); 
	return 0;
}

表达式不能确定main中调用fun是第几次调用的fun函数,在本电脑的运行结果是-10

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/662353.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-18
下一篇 2022-04-18

发表评论

登录后才能评论

评论列表(0条)

保存