操作符详解

1、操作符

1)算术操作符

+ - * / %

a.除了%之外,其余的几个操作符都可以作用于整数和浮点数

b.对于/操作符,如果两个操作数都是整数,则执行整数除法,只要有浮点数则执行浮点数除法

c.%的两个操作符必须是整数,返回整除之后的余数

2)移位操作符(二进制)

<<   //左移操作符
>>   //右移操作符

a.左移操作符移位规则:左边抛弃,右边补0

b.右移操作符移位规则:

   *算术右移:右边抛弃,左边补原符号位  

    逻辑右移:右边抛弃,左边补0

c.对于移位运算符,不能移动负数位

3)位操作符(二进制)

&    //按位与
|    //按位或
^    //按位异或

eg.统计一个数二进制位中‘1’的个数(举例:5)

#include <stdio.h>
int main()
{
  int a = 5;
  //101
  int b = 1;
  //001
  int count = 0; //原数字中1的个数
  int c = 0;
  do
  {
    c = a & b;
    if (c == 1)
    {
      count++;
    }

    a = a >> 1;

  } while (a);
  printf("%d", count);
  return 0;
}

4)赋值操作符

=  及其变式(比如+=)

5)单目操作符

!    //逻辑反操作
-      //负值
+     //正值
&     //取地址
sizeof     //操作符的类型长度(单位:字节)      -->sizeof是一个操作符,不是函数,并且括号中的表达式不参与运算
~      //对一个数的二进制按位取反
--     //前置、后置--
++   //前置、后置++
*      //解引用操作符
(类型)     //强制类型转换

 

sizeof举例:

void test1(int arr[])
  {
    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));   //40
  printf("%d/n", sizeof(ch));    //10
  test1(arr);                    //8
  test2(ch);                     //8
  return 0;
}

6)关系操作符

>    <    >=    <=    !=    ==

7)逻辑操作符

&&  //逻辑与
||  //逻辑或

注意区分逻辑与/或按位与/或的区别

举例:

 int i = 0, a = 0, b = 2, c = 3, d = 4;
  i = a++ && ++b && d++;      //a先使用后++,使用前为0,&&后不计算
  printf("a=%d/nb=%d/nc=%d/nd=%d/n", a, b, c, d);
  //打印:1 2 3 4
  a=1;
  i = a++ || ++b || d++;   //a为真,||后的不计算
  printf("a=%d/nb=%d/nc=%d/nd=%d/n", a, b, c, d);
  //打印:2 2 3 4

8)条件操作符

exp1 ? exp2 : exp3

9)逗号表达式

exp1, exp2, exp3……expn

从左向右计算,整个表达式的结果是最后一个表达式的结果

10)下标引用、函数调用和结构成员

a.下标引用操作符[]

    操作数:一个数组名+一个索引值

int arr[10];   //创建数组
arr[9]=10;    //实用下标引用操作符
//[]的操作数是arr和9

b.函数调用操作符():

    接受一个或者多个操作数,第一个操作数是函数名,剩余的操作数是传递给函数的参数

c.访问一个结构的成员.

    .结构体.成员名

    ->结构体指针->成员名

举例:

struct book
{
  char name[20];
  int price;
};
int main()
{
  struct book Book = {"C lan", 20};
  //方法一
  printf("书名:%s/n", Book.name);
  printf("价格:%d/n", Book.price);
  //方法二
  struct book *pb = &Book;
  printf("书名:%s/n", (*pb).name);
  printf("价格:%d/n", (*pb).price);
  //方法三
  printf("书名:%s/n", pb->name);
  printf("价格:%d/n", pb->price);
}

2、表达式求值

表达式求值的顺序的一部分是由操作符的优先级和结合性决定,同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型

3、隐式类型转换

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

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

举例:

char a,b,c;

c=a+b;

b和c的值被提升为普通整型,然后再执行加法运算,加法运算完成之后,结果将被截断,之后再存储到a当中。

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

整型提升的具体方法:按照变量的数据类型的符号位来提升

                           

  //负数的整型提升
  char c1 = -1; //变量c1的二进制位(补码)中只有8个比特位:11111111
                //因为char为有符号的char
                //在整型提升的时候,高位补充符号位,即11111……11111(32个1)
  //正数的整型提升
  char c2 = 1; //变量c1的二进制位(补码)中只有8个比特位:00000001
               //因为char为有符号的char
               //在整型提升的时候,高位补充符号位,即00……00(31个0)1
  //无符号数的整型提升,高位补0
  char a = 3;
  //00000000000000000000000000000011    --整型提升
  //00000011                            --截断
  char b = 127;
  //00000000000000000000000001111111    --整型提升
  //01111111                            --截断
  char c = a + b;
  //00000000000000000000000000000011
  //00000000000000000000000001111111
  //00000000000000000000000010000010    --相加
  //10000010    --  c
  //11111111111111111111111110000010  --补码
  //11111111111111111111111110000001  --反码
  //10000000000000000000000001111110  --原码
  printf("%d",c);  //打印整型c

整型提升例子

char c =1;
   printf("%u",sizeof(c));   //1
   printf("%u",sizeof(+c));  //4
   printf("%u",sizeof(-c));  //4
   printf("%u",sizeof(!c));  //4

4、算术转换

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

下面的层次体系称为寻常算术转换

long double
double
float
unsigned long int
long int
unsigned int
int

如果某个操作符的类型在上表中排名较,那么首先要转换为另外一个操作数的类型之后才能执行运算。

6、操作符的属性

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

     1)操作符优先级

     2)操作符的结合性

     3)是否控制求值顺序