重学c++之运算符和表达式

概述

在C语言中,表达式和语句是构成程序的基本元素。本节和下一章节我们就围绕它们展开讲一讲其中的C语言基础语法。

首先,让我们区分这两个概念:

  1. 语句(statement),语句是代码中的一个完整的,可以执行的步骤。

    1. 语句要么以";"分号结尾(简单语句),要么以"{}"代码块结尾(复合语句)
    2. 语句的作用复杂多样,常用于构建程序逻辑,如循环语句、条件判断语句、跳转语句等。
  2. 表达式(expression),表达式是由变量、常量(称之为操作数)运算符(也叫操作符)组成的序列,它总是会计算出一个值。

    1. 表达式可以非常简单,如一个单独的常量或变量,或者非常复杂,如包含多个运算符和函数调用的组合。
    2. 表达式的作用就是计算值、赋值、函数调用等。

在C语言中,语句和表达式实际上并没有明显的绝对界限,它们的关系是:

  1. 任何表达式只要直接加上一个分号,立刻就会成为一条语句。比如a = 10是一个赋值表达式,但只要加上";",就会变成一个赋值语句。表达式语句是语句最简单的形式。
  2. 语句不仅限于表达式,比如选择、循环等语句,语句可以更多的影响程序的逻辑。

在表达式中,最重要、最核心的就是连接表达式中常量、变量的运算符了,所以本小节我们主要研究C语言的运算符。

C 语言拥有异常丰富的运算符,比较常见和常用的有以下运算符:

  1. 算术运算符
  2. 赋值运算符
  3. 关系运算符
  4. 逻辑运算符
  5. 位运算符
  6. 三目运算符

这些运算符,又可以根据操作数的多少,分为:

  1. 一元运算符,只需要一个操作数的运算符
  2. 二元运算符,需要两个操作数的运算符,多数运算符都属于二元运算符。
  3. 三目运算符,自然就是需要三个操作数的运算符。

以上都比较简单,只介绍位运算符。

位运算符

移位运算符

它们分别是左移位运算符(<<)和右移位运算符(>>)。

移位运算符,可以通过将整数数据的二进制位向左或向右移动,来变换整数的二进制表示,从而改变整数值。

下面用两个表达式来描述移位运算符的基本作用,其中i是整数,j是一个正整数

  1. i << j:将 i 的位模式向左移动 j 位。

    1. 移出去的高位丢弃,并在低位补0。
    2. 实际上该操作相当于将i乘以 2j(如果没有溢出的话)
    3. 此表达式的主要作用是返回i移位运算后的结果
    4. 此表达式一般没有副作用,不会改变i变量的取值,移位运算符没有赋值的作用!!
  2. i >> j:将 i 的位模式向右移 j 位。

    1. 移出去的低位丢弃,如果i是无符号数或者非负值,则在左边补 0。
    2. 如果 i 是负值,其结果会根据编译器平台实现不同而不同:一些实现会在左边补 0,一些实现会在左边补 1。
    3. i是非负数的情况下,实际上该操作相当于将i除以2j(注意整数除法的结果还是整数)
    4. 此表达式的主要作用是返回i移位运算后的结果
    5. 此表达式一般没有副作用,不会改变i变量的取值,移位运算符没有赋值的作用!!

 注意:左移时如果发生了数据溢出将产生未定义行为,所以程序员在执行左移位运算时,需要认真思考移位的极限,避免溢出产生

编程语言中的右移位运算符(不仅仅C语言),通常有两种行为表现:

  1. 算术右移:算术右移会在高位插入符号位的副本(对于负数是1,正数是0),算术右移位运算通常用于有符号数,因为它可以保持整数的符号不变。

    1. 对一个负数进行算术右移会在高位补1。
    2. 对一个正数进行算术右移会在高位补0。
  2. 逻辑右移:逻辑右移不考虑整数的符号,总是在高位补0。逻辑右移显然不适用于移位有符号数,它用于移位无符号数。

C语言标准中规定,在右移位无符号数时,采用逻辑右移。但当右移位有符号数时,采取上述哪种行为取决于编译器平台的实现。

当然,在大多数现代编译器和平台上(比如MSVC/GCC/Clang等),右移位运算符都是算术右移的,也就是在现代编译平台上,右移位运算符不会改变有符号数的符号。

综上所述,关于右移位运算符的使用我们提出以下建议:

  1. 为了更好的平台移植性和安全性,可以直接对无符号数做右移位运算,这样就不会出现符号问题了。
  2. 如果要对有符号数做移位运算,请自行确认编译器行为,避免跨平台时出现移位符号问题。

扩展:

由于C语言在右移位运算上的灵活性,可能会导致一些"编码陷阱",所以C以后的高级编程语言一般都会对右移位运算符做更多的限制和规定。比如:

  1. Java会直接提供两个右移位运算符:算术右移(>>)和逻辑右移(>>>
  2. Python直接禁用了逻辑右移,总是执行算术右移。

按位运算符

按位位运算符包含:按位取反~,按位与&,按位异或^,按位或|。其中按位取反是一元运算符,其余都是二元运算符。

对于以下表达式:

~a:对a进行按位取反运算。也就是将 a 的每一位进行取反操作。即 0 变成 1,1 变成 0。

i & j:对 i 和 j 的每一位进行逻辑与运算。只有两个数的相应位都为1时,结果位才为1,否则为0。

i | j:对 i 和 j 的每一位进行逻辑或运算。只要两个数的相应位中有一个为1,结果位就为1,否则为0。

i ^ j:对 i 和 j 的每一位进行异或运算。如果两个数的相应位一个为0,另一个为1,则结果位为1,否则为0。(对应位不同结果就是1)

注意:

  1. 这些表达式的主要作为是返回位运算后得到的结果,没有副作用,不会改变任何一个操作数的值!!
  2. 在C语言中,&|不是逻辑运算符,而是位运算符,不要搞混淆了。

按位运算符中,比较需要留意的是按位异或。它具有以下一些非常优秀的性质:

a ^ 0 = a; 任何整数异或0得到的都是它本身

a ^ a = 0; 任意整数异或自己得到的都是0

a ^ b = b ^ a; 异或运算满足交换律

(a ^ b) ^ c = a ^ (b ^ c); 异或运算满足结合律

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值