目录
定义比较关系为什么不需要"< == > >= <="都定义?
定义比较关系为什么不需要"< == > >= <="都定义?
基于简单的数学公式:
- a < b ==> ! a >= b
- a ==b ==> ! a != b
- ! a < b && ! a == b ==> a > b
- ! a < b || a == b ==> a >= b
- a < b || a == b ==> a <= b
只需要实现<和== 或者 >和==即可定义所有关系运算符。C++/C#/Swift默认用前者,定义小于<和等于==运算符可以实现所有关系运算符操作。
关系运算符
判断相等或者不等的运算符,一般被称为关系运算符或者比较运算符。
相等和不相等
定义基本比较运算符:< > == >= <= !=
- C/ObjC/C++/Java/C#/PHP/Kotlin/Python/仓颉 等均支持基本比较运算符。它们使用"=="表示相等,"="表示赋值,"!="代表不相等。
- C/C++条件语句可以混用赋值和相等运算符,因为支持赋值运算符返回整数并作为判断条件。
- VB 特殊在用"="判断相等,"<>"或"><"代表不相等。
- JS中“=”是赋值,"=="判断相等,宽松比较,"==="是严格比较相等。
- 比如1 == "1"成立,但1 === "1"不成立。
- SQL和VB类似,用"="表示相等,"<>"表示不相等。“=“也用于赋值,根据场景区分开,不会混淆。比如set @variable = <value>表示赋值,在where子句中"="是比较。
- SQL为了更好支持查询,增加了BETWEEN/LIKE/IN, 分别表示在某个范围,类似和在确定范围内。其他编程语言不会有此功能。
- Fortran 有两套运算符表达关系运算符,== /= > >= < <=和.eq. .ne. .gt. .lt. .ge. .le.
- PHP 额外支持恒等===和非恒等!==运算符,===意味着不仅数值相同,类型也相同。!==表示数值和类型至少一个不同。
- 例如 "100" == 100 返回true, 但 "100" === 100 是false.
- Pascal 用 = 代表等于,<> 代表不等于。
优先级
- < > == >= 优先级高于 == 和 !=.
隐式/显式类型转换
编译器为了简化不同类型变量互操作,引入隐式转换。
隐式转换
- C/ObjC/C++/C# 等都支持隐式转换,"小"类型和"大"类型操作,"小"类型自动转换成"大"类型。但隐式转换很可能带来风险。
- 浮点数类型可以隐式转换成unsigned long long, 注意可能损失精度。
- Swift为了消除隐式转换的风险,规定不同类型变量运算,必须强制转换成相同类型
- 比如In8和Int32相加,Int8必须强制转换成Int32才能相加:a是Int8, b是Int32, b = Int32(a) + b
- 字面量运算不受如上限制,编译器会自动推导,例如var c = 1 + 0.1 - 仓颉 同样不支持隐式类型转换,对于二元运算符(除了幂运算符),两个操作数类型必须一致。包括但不限于算术运算符、关系运算符等。
不同的显式类型转换
- 仓颉
- Type(val)
例如Int64(3.5)
- Type(val)
- Swift
- Type(val)
- C/ObjC/C++/C#
- (Type)val
显示转换一定会成功?
- C# 显示转换只是程序员的一种想法,运行时遇到问题一样会抛出异常。
数值和布尔类型转换
- C/ObjC 布尔类型_Bool本质是整型,二者可以互相转换。
- C# 不允许数值和布尔互相转换。
运算符优先级有没有通用原则?
通用原则
- 单目运算符和操作数结合强,优先于双目运算符,双目运算符优先于三目运算符。
- 算术运算符经常使用,优先于关系运算符,关系运算符优先于逻辑运算符。
- 移位运算符依然属于数值运算,优先级偏高,高于关系和逻辑运算符。
- 大部分编程语言的运算符都是从左至右结合的,但是也有一些是从右至左结合的。例如,单目运算符(前缀后缀需要区分开)、三目运算符和赋值运算符是从右至左结合的。
- 大体规则:初级运算符( )、[ ]、->、. > 单目运算符(包含逻辑非!) > 算术运算符(先乘除后加减) > 关系运算符 > 逻辑运算符(不包括!, && > ||) > 条件运算符 > 赋值运算符 > 逗号运算符。
- C++支持运算符重载,运算符优先级不受运算符重载影响。
C语言标准的优先级
- C标准6.5章节介绍了不同类型表达式的优先级:n1570.pdf (open-std.org).
例如:如下移位表达式没有累加表达式优先级更高。
shift-expression:
additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression
从如上的表达式描述语义可以看到对优先级的定义。
C++优先级
- C++相比C语言,扩展了新的运算符,其它已有的运算符和C语言优先级一致。
- 范围解析::被列为第一优先级,类型名称typeid和类型转换const_cast/dynamic_cast/reintepret_cast/static_cast和C语言postfix-expression优先级为一组。
- new/delete运算符和unary-expression优先级为一组。
- 指向成员的指针.*和->*紧随上面unary-expression之后,在所有multiplicative-expression表达式之上。
- throw只比逗号运算符优先级高。
参考: C++ 内置运算符、优先级和关联性
其它语言优先级
- ObjC和C语言优先级完全一样。
- Java没有显式指针,运算符优先级和C语言一样,增加了instanceof操作符,表达式返回bool类型,预设优先级和比较关系运算符一样,高于判等运算符==和!=.
- C#运算符优先级和C语言一样,有增加一些关键字作为运算符。更多参考: C# 运算符和表达式
- Python相比C语言,增加了求幂运算符**, 优先级略高于unary operator. 另外,移除了&&、||和!逻辑运算符,改用and/or/not/is/in自然语言,它们的优先级等同。lambda表达式优先级最低。
- JavaScript运算符除了和C语言一样的之外,增加了全等===和不全等!==, 优先级和判等运算符一组。还增加了一元操作符delete new typeof void, 和C/C++一元运算符优先级类似,与++/--/-/~等运算符优先级为一组。
- Go语言和C语言运算符优先级保持一致,运算符更少,移除了前缀自增自减++/--, 只有后缀自增自减,优先级在第一梯队。
- VB 整除 "\" 比 除法 "/"和乘法 "*" 低:
15 \ 7 * 2 得到1, 而非4.
前缀和后缀自增自减运算符
- 也许你会在不同的书籍上看到对此有不同的描述,以自增为例,有的说后缀自增更低,有的说更高。
- 事实上,它们是分别从语言标准定义和最终运行结果来看,产生的不同说法。
- 以C标准primary expression角度,x++和x[1]数组访问都属于"主要"表达式,primary expression优先级比较高,会给人后缀++优先级很高的样子,其实语言并没有把++真放的很高,只是为了表达x++仅仅返回了x, 后缀++其实是副作用,不是语言认为的"主要意图"。从实际运行的角度,似乎后缀++优先级就很低了,因为它只是附带的。
优先级
编译器和解释器会对源代码运算数和不同运算符的组合感到困惑,用优先级解决先算什么后算什么。相同优先级的组合也会让编译器困扰应该先做什么,结合性应运而生。
优先级基本原则
编译型语言一般遵循如下优先级原则:
- 单目运算符优先于双目运算符,双目运算符优先于三目运算符。
- 算术运算符优先于关系运算符,关系运算符优先于逻辑运算符。
- 大部分编程语言的运算符都是从左至右结合的,但是也有一些是从右至左结合的。例如,单目运算符(前缀后缀需要区分开)、三目运算符和赋值运算符是从右至左结合的。
- 大体规则:初级运算符( )、[ ]、->、. > 单目运算符(包含逻辑非!) > 算术运算符(先乘除后加减) > 关系运算符 > 逻辑运算符(不包括!, && > ||) > 条件运算符 > 赋值运算符 > 逗号运算符。
C++支持运算符重载,运算符优先级不受运算符重载影响。
正则表达式优先级
- 正则表达式元字符不止一种,依然存在优先级问题。比如,方括号比后向引用优先级更高。
条件运算符
不少人都困惑为什么a ? b : c结合性是从右向左?事实上,大家可能按照从左向右来推导,先判断a是否为真,为真得到b, 否则得到c. 这是计算过程的方向,和优先级结合性没半毛钱关系。结合性判断的是如下表达式:a ? b : c ? d : e是先算a ? b : c还是先算 c ? d : e. 现在大家都知道应该先算后面了。
两种"括号"运算符
- (int)p->data的括号和(int)(p->data)的第二个括号是完全两种运算符,前者是类型转换(type), 后者(p->data)是纯正的括号运算符,优先级很高。
(int)p->data 不要被理解为先将p转换成int类型,而是先计算p->data, 然后强制转换为int.
运算符优先级易错示例
- C
- a << 2 - b ===> a << (2 - b)
- if (status & ENALBE != 0) ===> if (status & (ENABLE != 0))
- while (c = getchar() != EOF) ===> while (c = (getchar() != EOF))
- PHP && || 和 and or
- and和or虽然也是逻辑与和或,它们的优先级是小于&&和||的,需要特别注意。
若文章对您有帮助,欢迎关注 程序员小迷 。助您在编程路上越走越好!
微风不燥,阳光正好,你就像风一样经过这里,愿你停留的片刻温暖舒心。
我是 程序员小迷 (致力于C、C++、C#、Android、iOS、Java、Kotlin、Objective-C、Swift、Shell、JavaScript、TypeScript、Python等编程技术的技巧经验分享),若作品对您有帮助,请关注、分享、点赞、收藏、在看、喜欢,您的支持是我们为您提供帮助的最大动力。
1.您还可以访问 迷软科技 网站:https://www.minicoda.com
2.想学习更多知识,您可以关注 微信公众号 : 程序员小迷 ( miniminicode )(一个关注于C、C++、C#、Android、iOS、Java、Kotlin、Objective-C、Swift等语言软件开发技能技巧经验的公众号)