• <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;

          

         

        

  • 相关阅读:
    用Xamarin + VS 编写Android程序体验及其与Android Studio的比较
    【Android】XML文件的解析
    【Ubuntu】您没有查看“sf_VirtualDisk”的内容所需的权限。
    Android酷炫实用的开源框架(UI框架)
    Linux下安装gcc 、g++ 、gfortran编译器
    Ubuntu 分辨率调整及操作问题解决
    “this kernel requires an x86-64 CPU, but only detects an i686 CPU, unable to boot” 问题解决
    【Android】沉浸式状态栏实现
    【Android】基于TCP协议的网络通信
    C#中string和byte[]相互转换问题解决
  • 原文地址:https://www.cnblogs.com/mokang0421/p/7367764.html
Copyright © 2020-2023  润新知