C语言教程

您所在的位置:网站首页 c语言的复制运算符 C语言教程

C语言教程

2024-07-09 10:21| 来源: 网络整理| 查看: 265

注意,本章讲解的优先级,求值顺序,副作用极其重要,甚至一些十分熟悉C语言的老手也可能会犯相关的错误!

运算符 什么是运算符

我们在前面讲解过表达式,语句的概念,也讲解并使用了一些基本的运算符,例如四则运算,赋值运算符等.

这一部分我们将会详细扩充一些运算符,并仔细讲解运算符与表达式求值的一些重要细节.

运算符和表达式不可分割,我们再来看一下标准中对表达式的描述:

再看一下Microsoft文档中关于操作数的描述:

image-20230930224827531

也就是说,运算符及其操作数的序列组成一个表达式.单一的运算符无法发挥作用,必须至少有一个对应的操作数才能构成一个表达式.至于操作数的概念很好理解,简单来说就是参与运算的各种值.

下面来详细细分一下C语言中的各种运算符.

基本运算符

我们之前已经大量的使用了这些运算符.

赋值运算符: =

C语言中,一个单独的=并不意味着"等于",这和Visual Baisc等语言并不相同,他是一个赋值运算符.例如:

a = 3;

用于将=右边的值3赋给左边的变量a.也就是说,=左边是一个变量名,右侧是将要赋给该变量的值.

赋值行为是从右向左的.

进一步注意,我们需要区分变量名和变量值的区别,尽管他们的区别可能微乎其微,但是如果我们有:

i=i+1;

显然这个合法的语句在数学上行不通,但是,C语言中,这代表着把变量i的值加上1,然后将新值重新赋值给i变量.

另一方面,类似这样的语句是错误的:

3 = a;

因为3是一个常量,你不能对其进行修改---无论是从语法上还是从逻辑上都不正确.很显然,3就是3,我们当然不能把3"赋值"为4.实际上,我们判断这样的语句是否合法,看的是=左边是否为一个左值,更准确的说,是可修改的左值.

数据对象,左值,右值

这部分可参考C Primer Plus第六版的对应内容!

赋值表达式的实际效果是将某个值存储到某个指定的内存位置上,这一段指定的数据存储空间称之为数据对象,也许有些朋友了解过面向对象和面向过程的区别,请不要混淆,这里的"对象"指的是操作的焦点.C标准只有在这时才会使用对象这个术语.

C语言中,所谓左值就是用于标识特定数据对象的名称或表达式,所以,对象指的是实际的数据存储,而左值实际上是一个用于标识或定位存储位置的标签.例如a=3;中a就是标识了变量a的位置,编译器根据这个标签找到变量a的存储位置,最后把值3存储进去.

此外,上面还提到了表达式,而不仅仅只是一个简单名称,这意味着,只要能够正确标识一个位置,就是一个左值.关于这部分内容,我们需要学习到后面才能知道,例如可以使用数组下标运算符指定数组元素等,我们先不急.

我们还提到了可修改的左值,之所以说这个,是因为C标准中新增了(2023年早就已经不是新增了)const限定符,用const创建的变量的值不可变(我们之前讲解使用常量时提到过).那么,用const修饰过的变量自然不能作为=运算符的左操作数.

而至于a=3;中的3,相应的,是一个右值.右值指的是能赋给可修改左值的量,且本身不是左值.

总的来说,使用一个=运算符需要两个操作数,左侧(左操作数)必须为一个可修改的左值,而右侧(右操作数)既可以是左值也可以是一个右值,当然,一个不可修改的左值也可以作为右操作数.

加法运算符: +

+的使用非常显而易见,但是我们需要注意的是,+的左右两个操作数无论是否为右值,最后加法运算的结果(也就是这个表达式的值)一定是一个右值.

例如:

a+b中,a和b都是左值,但是a+b计算出来的值,也就是表达式a+b是一个右值.

减法运算符: -

同理,它用于减法运算,和+一样,需要两个操作数.

+和-都需要两个操作数,所以他们都是二元运算符.

符号运算符: +和-

这里和加法,减法运算符使用相同的符号,但是一定注意,他们是不同的!

因为我们可以有这样的一个表达式:

+a

或者

-a

这意味这此处的+或-仅仅需要一个操作数,所以他们都是一元运算符,其作用也很简单---取相反数.

不过在过去,+a是不被允许的.

乘法和除法运算符: *和/

关于这两个表达式之前就说过了,他们也是二元运算符.需要注意的是,别忘了除法运算符有截断这个特性(整数除法结果的小数部分被丢弃).

重点:运算符优先级和求值顺序

我们现在仅讲解了基本运算符,我们拿这些简单的运算符进行举例.

优先级

优先级和数学上运算符优先级的意义是类似的,与数学相似,无论是加减乘除,还是赋值等运算符都有不同的优先级,如果一个表达式有多个运算符,我们首先根据优先级来确定表达式的运算顺序.

考虑下面的代码:

sum = 12.0 + 40.0 * n / part;

假设n的值为2,part的值为4.

这条语句中的赋值运算符右面有加法,乘法和除法运算符,先算哪一个?这里无需废话,和数学一样,先算乘除法,再算加减法,但是这是我们一眼看出来的,如果是C编译器来处理这段代码,则必须有提前规定好的运算顺序,也就是先算乘除法,再算加减法.

C语言中对此问题有着明确的规定,为每一个运算符都规定了各自的优先级,优先级高的运算符(乘除法)先执行运算,然后返回的结果再继续和优先级低的运算符(加减法)结合执行运算,这样,上面的代码如何运算就非常明确.

如果两个运算符的优先级相同怎么办?如果他们处理同一个运算符对象,则根据他们在语句中出现的顺序而言,大多数运算符都是从左向右依次运算(=运算符除外).

如此,上面的语句是如此执行:

40.0 * n 首先计算*或/,发现他们处理同一个操作数n,则根据从左向右结合的顺序,先计算*,结果是80.0

80.0 / part 然后计算/,结果为40.0

12.0 + 40.0 最终结果为52.0

到目前为止,我们学习过的运算符的优先级:

image-20231004211804464

注意对于C语言而言,符号运算符和加减法运算符是不同的,首先他们的操作数的数量就不同.

求值顺序

为了解决运算顺序,C语言明确规定了运算符的优先级,但是这并没有规定所有的顺序,来看下面的代码:

y = 6 * 12 + 5 * 20;

当运算符共享一个运算对象时,优先级确定了求值顺序,再进一步,如果优先级相同(例如乘除),那么结合性进一步确定求值顺序.

但是,上面这个语句中,有两个乘法运算.显然这两个乘法比加法先进行运算,但是问题来了:这两个乘法先算哪个.

实际上,C语言并未规定这两个乘法先计算哪一个,这取决于具体实现---意味着不同的电脑(计算机),甚至是一台电脑上不同的编译器运行出来的结果也不相同---有可能先算前者的实现在A硬件上效率更高,在B硬件上反而更适合先算后者.这种未明确规定的行为叫做未定义行为,这里就是一个关于求值顺序的未定义行为,他们十分重要!

许多朋友可能认为这并不是一个问题,事实上非常重要,不清晰的代码甚至可能引发严重的问题(我们会在后面介绍到其他运算符后并重新讲解副作用时进行举例).

不过,就上面的这样代码而言,先算后算并没有影响,因为4个操作数都是常数,也就不存在副作用的影响,最终的结果显然不变.

其他算数运算符

学习这节之前,要学会进制转换,并尽量了解原码,补码和反码.

求模运算符: %

%运算符用于求a除以b的余数,该运算符要求左右两个操作数必须均为整数.

关于正数,没有任何问题.

对于负数而言,例如-8%3,其结果要多注意一下.

我们有公式:A % B = A - A / B * B

或者可以简单记忆规律:

取模运算结果的正负是由左操作数的正负决定的.如果%左操作数是正数,那么取模运算的结果是非负数;如果%左操作数是负数,那么取模运算的结果是负数或0

位运算符: &,|,^,

位运算的位,指的是二进制位,也就是说,位运算直接以二进制来处理操作数.

按位与: &

二者皆为1,结果才为1,否则为0

例如 3 & 1的结果为1

即二进制011和001按位与运算,结果为001,也就是十进制1

按位或: |

二者皆为0,结果才为0,否则为1

例如 3 | 2的结果为3

即二进制011和010按位或运算,结果为011,也就是十进制3

按位异或: ^

二者相同为0,不同为1

例如 4 ^ 2的结果为6

即二进制100和010按位异或运算,结果为110,也就是十进制6

左移运算符:


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3