<C和指针---读书笔记5>

操作符和表达式

在笔记4中,介绍了C语言的基本循环语句.本节将介绍C语言中 变量五花八门的操作.

操作符: 

     分成了算数操作符、移位操作符、位操作符、赋值操作符、单目操作符、关系操作符、逻辑操作符、条件操作符、逗号操作符等等....

算数操作符: 包括 +  -  *   /   %

      注意:   5/2 =2 , 整数相除,直接舍掉小数部分,不会进行四舍五入。

      % 取模运算,只接受整数之间的取模。

      整数和浮点数进行 + - * / 结果,结果是浮点数,还要看赋值运算符左边变量的类型.

移位操作符 :  << 和 >>

          左操作数的将进行移位,移动位数 n=右操作数值。方向为向左或向右。 如 011 <<3 , 将会 011000

          其实左移右移都是分:逻辑移位和算数移位的.  

          但在底层硬件中: 逻辑左移和算数左移都是执行高位舍弃,地位补0的操作。使得逻辑左移和算数左移结果一直保持一致。

                    (汇编码SAL 指令同 SHL,是同一条指令的两种助记符,执行的同一操作)

          但在底层硬件中:    逻辑右移和算数右移是不一样的, 逻辑右移: 高位补0,地位舍弃.  算数右移: 高位补符号位,地位舍弃.

                    (汇编SAR 与 SHR 不同,SHR左边高位补0,而 SAR 补的不是0,而是原来的符号位。)

C语言标准对 "无符号数"的左右移位,做了明确的规定 :  无符号数的左右移位均是逻辑移位。

但对"有符号数"的左右移位,没有明确规定,导致各个编译器可能会有差别. 

故:  C语言中出现  符号数右移的,是不能可靠移植的.   故我们见到的>> ,都需要先声明 unsigned

         还有一个问题:     因为编译器不一定支持 算数右移,那当我们想用算数右移的时候, 怎么写?

答案是: 需要我们用简单的代码去实现. 比如判断正负数然后执行不同的,,,

      假如右侧移位值n是一个负数, 该怎么移位? 这些情况,C标准中都没有说,具体就得看编译器怎么实现的了,所以尽量避免这种

情况,  属于不可移植的代码.

 位操作符: & | ^  

     这里没有将 ~ 放进来是因为 :   & | ^需要两个操作数. ~ 是针对单个操作数.

     主要用途是: 于移位寄存操作符配合,完成对一位的置1或清0操作。

     rega   | = (1 << n )   把寄存器的第n位置1

     rega   &= ~(1 <<n)  把寄存器的第n位清0.   请不要质疑,  如8位寄存器, ~ (00100000) = 11011111

赋值操作符: =

     在C语言中 a = x+3 ; 我们都能理解,把x+3的值,赋值给a.

     其实 = 是个赋值操作符, a=x+3 是一个赋值表达式(注意不加;) ,表达式就有结果。

     C语言规定赋值表达式的结果是左侧操作数的结果.

我们看这样一个程序:

#include <stdio.h>
int main(int argc,char **argv) { int a = 0; while(a=1) { printf("a=1 "); } }

我们想表达的意思是 如果 a = 1,就一直打印 "a=1", 但是误操作了  while(a==1) 错写成  while(a=1) 

这里导致的结果就是:  a=1 这个赋值表达式的结果是 a的新值1. 即while(1) ,陷入了死循环.如下图

从这个地方,我们也能反推,帮助理解赋值表达式是有结果的.

复合赋值符: 这个就是  a  += 1 ;a |= 1 << 3,写法简单、易读。

单目操作符

 单目操作符:有 ~ !  +-   ++  --   & *   sizeof        (类型) 这几种

  ~:  安位取反。 有时候  ~(0x1) :其实得到的是 1111 1111 1111 1110

  !: 是逻辑取反。 0x11得到的是 0. 

± : 单纯的正负号,无特别的意义。

++、-- 操作: 它由分成前缀、和后缀两种。 如 a ++     ++a

int main (void)
{
    int a, b,c,d ;
	a = b = 10;
	c = a ++ ;
	d = ++b; 
	printf("ch=%d %d %d %d
",a,b,c,d);   

}

  

从抽象的层次可以这样解读: ++a 和a++ 返回的结果均是一份拷贝值。

                                                ++a 是先执行 a=a+1操作后,再拷贝的a值,即新值

                                                a++ 是先拷贝的a值,然后再执行a=a+1.故而可以看出这两个表达式返回值存在不同。

 

 *  & 更像是一对,   &用于获取变量的物理地址信息; * point 用做右值时,表示会的 物理地址point的内容,用作左值时,表示存储位置。

 

sizeof ()  括号内部可以是一个 数据类型名称、也可以使一个变量、或表达式。 用于获知所占字节数.

(类型) 是强制类型转换操作,在特别处理上还是有存在的必要的。比如除法操作.

 

关系操作符

     主要包含 >  >=  < <= != ==     一定注意 == 和 =  在 if()的本质区别。

逻辑操作符   &&  ||

    跟位操作符有些类似,但 a  &&  b  表示 条件a和条件b都为真, 整个表达式才为真。

                                            a & b 则是 a的每一位 与b的对应位 做与运算.

    BK2535 ATE测试的时候,有因为该问题导致过问题.

条件操作符

           out =  a ?  1 : 0 ; 三目表达式. 可以替代一些简单的if else表达式.

逗号操作符

           expression1 , expression2 , ....expression m 这个表达式:  从左到右执行,并返回最终的结果----expression m的值.

因此在下面一种情况下常用:

         fifo_empty = fifo_state & 0x01 ;

         while(! fifo_empty) {

              rdata =  data_reg;

             fifo_empty = fifo_state & 0x01 ;

          }

   为了读空fifo,则需要每次判断fifo_empty是否为空.

          while(   fifo_empty = fifo_state & 0x01 ,   ! fifo_empty )

                       rdata =  data_reg;

      

     

    

原文地址:https://www.cnblogs.com/mokang0421/p/7367764.html