目录
一元运算符"-"一定要和变量名连在一起吗?
对于大部分编程语言而言,并不需要,因为它们是自由风格,"-"和变量名都是Token, 不连在一起,编译器或者解释器可以理解。
- Swift语言要求一元运算符必须紧随对应的操作数或变量。
- 1是错误的表示,-1是正确的表示。 - Fortran语言建议一元运算符如果紧跟在一个算术运算符之后,可能会提示警告:
i = j * -k
Warning: Extension: Unary operator following arithmetic operator (use parentheses)
一元运算符
二元和三元运算符的运算数和运算符的位置比较固定,一元运算符可能在运算数之前,也可能在之后。这产生一些有趣的形式。
可叠加
- 一元正号运算符和负号运算符都可以叠加。
- + + + +a还是a, - - - -a也是a.
- - + a得到-a, + - - a得到a.
- +a + - + + b * +c是a - b * c.
- ++++a和----a会编译出错,如编译器扫描按最长字符模式会认为是自增或自减的复合操作。
自增自减
大部分现代编程语言都支持++和--, 提供快速加1和减1的操作。汇编语言inc和dec与此对应,最早在Algol 68就已经有自增和自减运算符。它在B语言和C语言中得到发展,成为简洁的代表。Fortran和COBOL并没有自增和自减运算符,和C语言同时代的Pascal也没有,Pascal使用函数inc/dec完成。
正号负号
- C/ObjC/C++/Java/C#/Kotlin 等编程语言均支持一元正号和负号运算符。
一些新颖或简化的运算符
编程语言发展的一个重要因素就是更新的运算符代替已有的复杂逻辑。
- Swift空合运算符 ??
a != nil ? a! : b 可以用 a ?? b代替 - Swift区间运算符 ...和..<
例如一段区间1, 2, 3, 4可以用1...4或者1..<5代替 - Kotlin 提供范围运算符 .. 可以指代一个范围。
例如 1..2代表1到2.
为什么逻辑运算符有设计成短路处理?
为了优化性能和防止继续处理带来的逻辑错误。&&和||都支持短路处理。有时我们想先判断文件不为空然后去读取文件:
if (file && read(file))
如果file是空,还继续处理read将导致意外,短路处理反而很利于这种代码的编写。
运算符优先级有没有通用原则?
通用原则
- 单目运算符和操作数结合强,优先于双目运算符,双目运算符优先于三目运算符。
- 算术运算符经常使用,优先于关系运算符,关系运算符优先于逻辑运算符。
- 移位运算符依然属于数值运算,优先级偏高,高于关系和逻辑运算符。
- 大部分编程语言的运算符都是从左至右结合的,但是也有一些是从右至左结合的。例如,单目运算符(前缀后缀需要区分开)、三目运算符和赋值运算符是从右至左结合的。
- 大体规则:初级运算符( )、[ ]、->、. > 单目运算符(包含逻辑非!) > 算术运算符(先乘除后加减) > 关系运算符 > 逻辑运算符(不包括!, && > ||) > 条件运算符 > 赋值运算符 > 逗号运算符。
- 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、C++、C#、Android、iOS、Java、Kotlin、Objective-C、Swift、Shell、JavaScript、TypeScript、Python等编程技术的技巧经验分享),若作品对您有帮助,请关注、分享、点赞、收藏、在看、喜欢,您的支持是我们为您提供帮助的最大动力。