操作符与表达式 2.014

6/24、25更新

6/7更新(版本差异在8.1中)

6/5更新,6/4 更新(12--结尾),原名d语言操作符,现改名为 操作符与表达式,因为它们密切相关。
根据表达式一章作了一些更新, $这个符号的作用还是没搞清楚,看得头大!

$ 这个符号是指数组的 length 属性,只能用在 [ ] 中 (oldrev贡献)
// 下面这些表达式是等价的: [color=red]6/5更新[/color]
bar[ ]
bar[0 .. 4]
bar[0 .. length]
bar[0 .. $]
bar[0 .. bar.length]


特征符:
Identifier             标识符
StringLiteral 单个字符串文字
CharacterLiteral 字符文字
IntegerLiteral 整数文字
FloatLiteral 浮点数文字
Keyword 关键字

/ 除取整 15除以2商的整数部分7 DivideByZero 异常
/= 除取整赋值
. 全局作用域运算符 对象操作符,在模块作用域级别查找名称
技巧1:
int x;
int foo(int x)
{
if (y)
return x; // 返回的是 foo.x,而非全局的 x
else
return .x; // 返回的是全局的 x
}

.. 数组分割符,参见 $
... 函数多参数 //参见参数可变型函数

& 按位与 或 返回操作数地址 ? And表达式 & Cmp表达式
&= 按位与赋值
&& 逻辑与 AndAnd表达式 && Or表达式
| 按位或 Or表达式 | Xor表达式
|= 按位或赋值
|| 逻辑或 OrOr表达式 || AndAnd表达式
- 减 或 位反

-= //
-- //
+ //
+= //
++ x=m++ 表示将m的值赋给x后, m加1。
x=++m 表示m先加1后, 再将新值赋给x。


< //
<= //
<< 左移
<<= 左移赋值
<> //
<>= 3 小于,等于或大于 ??
> //
>= //
>>= 右移赋值
>>>= 右移赋值,左边空出的位以0填充
>> 右移
>>> 无符号右移(逻辑右移)
! 逻辑非 //各类型的比较方式不同,参考 表达式 一节
或者用于 显示模板实例化

!= 不相等 bool
!<> 4 未定义或等于
( “未定义”的意思是有操作数为 NAN 。)
!<>= 5 未定义
!< 未定义、大于或等于
!<= 6 未定义、或大于
!> 未定义、小于或等于
!>= 7 未定义、或小于

(
)
[
]
{
}
? 三目运算符 如: <表达式1>?<表达式2>:<表达式3>;
, 将多个表达式串在一起, ","运算符的左边总不返回,右边表达式的值
才是整个表达式的值。例如:
x=50;
y=(x=x-5, x/5); 等同于 y=(x-5)/5 ,最后y=9

; 8
: 参见 ? 符

$ 指数组的 length 属性,只能用在 [] 中 (oldrev贡献)
// 下面这些表达式是等价的: 6/5更新
bar[ ]
bar[0 .. 4]
bar[0 .. length]
bar[0 .. $]
bar[0 .. bar.length]


=
== 相等 bool
class C;
C c;
if (c == null) // error
...
if (c is null) // ok


* 对"&"运算符的一个补充, 它返回位于这个地址内的变量值
*= 取地址内的变量值 赋值
% 取模。15除以2的余数部分1(d支持浮点数,和c不同) DivideByZero 异常
%= 取模赋值


^ 按位 异或 Xor表达式 ^ And表达式
^= 按位 异或 赋值
~ 非(取反) ?? 或用于连接数组,最后生成一个动态数组
~=

is 比较同一性 bool 不能被重载
! is 比较非同一性
in 检测一个元素是否在关联数组中 null,或指向该元素的指针。


参见"一元表达式" 和 "基本表达式"





问题: main()
{
char m, n; /*定义字符型变量*/
m='c'; /*给m赋小写字母'c'*/
n=m+'A'-'a'; /*问题1: 将c中的小写字母变成大写字母'B'后赋给n*/
...
}

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。


表达式


C 和 C++ 程序员会发现 D 中的表达式很熟悉,另外还有一些有意思的扩充。
表达式用来计算多个值并返回一个特定类型的值。随后,所得的值可以被用于赋值、测试或
被忽略。表达式也可能有副作用。

8.1 求值顺序

  1.030
The following binary expressions are evaluated in strictly left-to-right order:

CommaExpression, OrOrExpression, AndAndExpression

The following binary expressions are evaluated in an implementation-defined order:

AssignExpression, OrExpression, XorExpression, AndExpression,
CmpExpression, ShiftExpression, AddExpression, CatExpression,
MulExpression, function parameters



  2.014
The following binary expressions are evaluated in strictly left-to-right order:

OrExpression, XorExpression, AndExpression, CmpExpression,
ShiftExpression, AddExpression, CatExpression, MulExpression,
CommaExpression, OrOrExpression, AndAndExpression

The following binary expressions are evaluated in an implementation-defined order:

AssignExpression, function parameters



除非特别说明,否则,实际的实现是以任意顺序自由计算表达式的各部分。当它不是特定的
的时候,依赖于求值顺序就是个错误。例如,下面的就是非法的:
i = i++;
c = a + (a = b);
func(++i, ++i);
如果编译器能够确定表达式的值是依赖于求值顺序的话,它将报告一个错误(但这不是必须
的)。检测这种错误的能力是实现的质量方面的问题。


8.2 表达式

表达式:
赋值表达式
赋值表达式 , 表达式

先计算“,”左面的操作数,然后计算右面的操作数。表达式的类型是右面的操作数的类型,
表达式的结果是右面的操作数的结果。


8.3 赋值表达式

赋值表达式:
条件表达式
条件表达式 = 赋值表达式
条件表达式 += 赋值表达式
条件表达式 -= 赋值表达式
条件表达式 *= 赋值表达式
条件表达式 /= 赋值表达式
条件表达式 %= 赋值表达式
条件表达式 &= 赋值表达式
条件表达式 |= 赋值表达式
条件表达式 ^= 赋值表达式
条件表达式 ~= 赋值表达式
条件表达式 <<= 赋值表达式
条件表达式 >>= 赋值表达式
条件表达式 >>>= 赋值表达式

右面操作数的类型会被隐式地转换为左面操作数的类型,并赋给左面的操作数。结果的操作
数的类型是左值得类型,结果的值是赋值后左值的值。

左面的操作数必须是左值。

8.3.1 赋值运算符表达式

赋值运算符表达式,如:
a op= b

在语义上等价于:
a = a op b

差别是操作数 a 只计算一次。


4、条件表达式
OrOr表达式
OrOr表达式 ? 表达式 : 条件表达式


5、OrOr 表达式

AndAnd表达式
OrOr表达式 || AndAnd表达式


6、AndAnd 表达式
Or表达式
AndAnd表达式 && Or表达式


7、Bitwise(按位)表达式
操作数必须是正数类型。否则,应用会做默认的正数提升

7.1 Or 表达式
Xor表达式
Or表达式 | Xor表达式
执行‘或’运算。

7.2 Xor 表达式
And表达式
Xor表达式 ^ And表达式
执行‘异或’运算。

7.3 And 表达式
Cmp表达式
And表达式 & Cmp表达式
执行‘与’运算。

8、 比较表达式
And表达式:
相等表达式
同一表达式
关系表达式
In表达式

9、 相等表达式
移位表达式
移位表达式 == 移位表达式
移位表达式 != 移位表达式
移位表达式 is 移位表达式
移位表达式 !is 移位表达式

对于复数,
相等定义为等价于:
x.re == y.re && x.im == y.im

不相等定义为等价于:
x.re != y.re || x.im != y.im

对于类和结构对象,
  (a == b) 被写成 a.opEquals(b),
而 (a != b) 被写成 !a.opEquals(b)


For class objects, the == and != operators compare the contents of the objects. Therefore,
comparing against null is invalid, as null has no contents. Use the is and !is operators
instead.
对于类对象,相等 用 == 和 != 操作符比较, null 用 is 和 !is 代替。
class C;
C c;
if (c == null) // error
...
if (c is null) // ok
对于数组(静态和动态),相等被定义为数组长度相等,并且对应的元素都相等。


10、 同一表达式 is
移位表达式 is 移位表达式
移位表达式 !is 移位表达式
is 用于比较同一性。如果要比较非同一性,使用 e1 !is e2。结果的类型是布尔型。在比较之前,操作数会通过常用的转换,转型为它们的一个公共类型。
同一运算符 is 不能被重载。

[color=red]5/16:添加以下[/color]
11 关系表达式
移位表达式
移位表达式 < 移位表达式
移位表达式 <= 移位表达式
移位表达式 > 移位表达式
移位表达式 >= 移位表达式
移位表达式 !<>= 移位表达式
移位表达式 !<> 移位表达式
移位表达式 <> 移位表达式
移位表达式 <>= 移位表达式
移位表达式 !> 移位表达式
移位表达式 !>= 移位表达式
移位表达式 !< 移位表达式
移位表达式 !<= 移位表达式
首先,会对 操作数应用 整数 提升。返回 bool。
对于类对象来说,Object.cmp() 的结果构成了左操作数,0 构成了右操作数。
关系表达式 (o1 op o2) 的结果是:
(o1.opCmp(o2) op 0)
如果对象为 null,进行比较就是错误。

对于(静态和动态)数组来说,关系 op 的结果是操作符应用到数组中第一个不相等的元素的结果。如果两个数组相等,但是长度不同,较短的数组“小于”较长的数组。(???)

11.1 整数比较
如果两个操作数都是整数类型,就会进行整数比较。
运算符    关  系
< 小于
> 大于
<= 小于等于
>= 大于等于
== 相等
!= 不相等
如果 <、<=、> 或 >= 表达式中操作数必须同是有符号数,或同是无符号数,否则会被视为错误。(可以使用类型转换)

11.2 浮点数比较
如果有浮点数,则执行浮点数比较。
任何有实用价值的浮点操作都必须支持 NAN 值。尤其 关系 运算符要支持 NAN 操作数。浮
点数的关系运算的 结果 可以是小于、大于、等于或未定义(未定义的意思是有操作数为
NAN )。
这意味着有 14 可能的比较条件:
运算符  大于  小于  等于  未定义      异  常          关     系
== T 否 相等
!= T T T 否 未定义、小于或大于
> T 是 大于
>= T T 是 大于等于
< T 是 小于
<= T T 是 小于等于
!<>= T 否 未定义
<> T T 是 小于或大于
<>= T T T 是 小于,等于或大于
!<= T T 否 未定义或大于
!< T T T 否 未定义、大于或等于
!>= T T 否 未定义或小于
!> T T T 否 未定义、小于或等于
!<> T T 否 未定义或等于
注解:
1. For floating point comparison operators, (a !op b) is not the same as !(a op b).
2. “未定义”的意思是有操作数为 NAN 。
3. “异常”的意思是如果有操作数是 NAN ,则产生 Invalid 异常 。它并不是个抛出的
异常。Invalid 异常 可以使用位于 std.c.fenv 里的函数来进行检查。

11.3 类比较
对于类对象,关系运算符会比较这些对象的内容。 因此,如果跟 null 进行比较就是无效
的,因为 null 没有内容。
class C;
C c;
if (c < null) // 出错
...


12 In 表达式
In表达式:
移位表达式 in 移位表达式
可以检测一个元素是否在关联数组中:
int foo[char[]];
...
if ("hello" in foo)
...

in 表达式同关系表达式 <, <= 等有相同的优先级。 In表达式 的返回值是 null,如果元素不在数组中的话;如果它在数组中,则它是一个指向该元素的指针。

13 移位表达式
求和表达式
关系表达式 << 求和表达式
关系表达式 >> 求和表达式
关系表达式 >>> 求和表达式

操作数必须是整数类型,并且会使用常用的整数提升。结果的类型是左操作数提升后的类
型。结果的值是左操作数移动右操作数指定的位得到的值。
<< 是左移。>> 是有符号右移(译注:也叫算术右移)。>>> 是无符号右移(译注:也叫逻
辑右移)。

如果要移动的位数超过了左操作数的位数,会被认为是非法的:
int c;
c << 33; // 错误

14 求和表达式
求和表达式:
求积表达式
求和表达式 + 求积表达式
求和表达式 - 求积表达式
连接表达式

如果操作数是整数类型,会应用整数提升,然后会通过常用的算术转换提升为它们的公共类
型。
如果有操作数为浮点类型,另一个操作数会被隐式地转换为浮点类型,然后会通过常用的算
术转换提升为它们的公共类型。

如果运算符是 + 或 -,第一个操作数是指针,并且第二个操作数是整数类型,结果的类型就
是第一个操作数的类型,结果的值是指针加上(或减去)第二个操作数乘以指针所指类型的
大小得到的值。

如果第二个操作数是一个指针,而第一个操作数是一个整数,并且操作符是 +,则会按照上
面所说的方式进行指针运算,只不过操作数的顺序反过来。

浮点操作数的求和表达式不是可结合的。

15 连接表达式
求和表达式 ~ 求积表达式

连接表达式 用于连接数组,最后生成一个动态数组。这些数组必须具有相同元素类型。如
果有个操作数是一个数组,而另一个是那个数组元素类型的操作数,则该数会被转换成一个
包含它的长度为 1 的数组,然后完成连接操作。

16 求积表达式

一元表达式
求积表达式 * 一元表达式
求积表达式 / 一元表达式
求积表达式 % 一元表达式

操作数必须是算术类型先会执行整数提升,然后会通过常用的算术转换提升为它们的公共类
型。

于整数操作数来说,*、/ 和 % 对应于乘、除和取模运算。对于乘运算,会忽略溢出,结果
会简单地截取为整数类型。如果除或者取模运算的右操作数为 0 ,会抛出一个
DivideByZero 异常。

对于 % 操作符的整型操作数,如果操作数为正,则结果符号为正;否则结果符号由具体实
现定义。

对于浮点操作数来说,各种运算同对应的 IEEE 754 浮点运算相同。
浮点数的积表达式不是可结合的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值