其它常用运算符
最后我们列举一些其它我们现在需要掌握得其它运算符。实际上,还有许多其它的运算符我们尚未学习。
条件运算符
条件运算符可以在表达式内部形成一个分支结构。
运算符 | 名称 | 作用 |
---|---|---|
a ? b : c | 条件运算符 | 形成分支结构 |
条件表达式是唯一的三元(三目)表达式。它的写法如下:
操作数1 ? 操作数2 : 操作数3
这个表达式的求值也比较形象。若“操作数1”为 true
(或能隐式转换为 true
),则对“操作数2”求值并以“操作数2”的值为整个表达式的值。反之,若“操作数1”为 false
(或能隐式转换为 false
),则对“操作数3”求值并以“操作数3”的值为整个表达式的值。
我们可以用 if
- else
结构进行类比。例如:
max = (a > b) ? a : b;
相当于:
优先级和结合方向
条件运算符的优先级与赋值运算符相同。由于条件运算符的三元特殊性,故 ?
与 :
中间的操作数如同视有括号,不考虑优先级。
条件运算符的结合方向为从右向左。 **
逗号运算符
逗号运算符并不进行实际的运算,它的主要作用是先后求值两个表达式。
运算符 | 名称 | 作用 |
---|---|---|
a, b | 逗号运算符 | 求左侧操作数,然后求右侧操作数 |
逗号表达式的写法:
左侧操作数, 右侧操作数
这里的操作数一般是表达式。当求逗号表达式的值的时候,会先求左侧操作数的值并抛弃,再求右侧操作数的值。最终将右侧操作数的值作为整个逗号表达式的值。
举个例子:
x = (a = 3, 42 + 1);
这里的 a = 3, 42 + 1
就是逗号表达式。正如上所述,先求左侧操作数 a = 3
的值,将 a
赋值为 3
并求得值为 3
(但是这个值会被抛弃掉)。然后求右侧操作数 42 + 1
的值为 43
。因此整个表达式的值就是 43
。 逗号表达式在循环语句中有一些用处。比如:
这里的循环条件先读取一个用户输入,然后判断用户输入是否等于 'm'
。这样可以一定程度上让程序代码变得简洁。如果你没有理解这个例子也没有关系,它并不重要。
优先级和结合方向
逗号运算符的优先级在 C++ 中最低。 逗号运算符的结合方向为从左向右。这意味着你可以写这样的表达式:
expr1, expr2, expr3, ..., exprn
它将从左向右求 expr1
, expr2
…… exprn
的值,并以 exprn
的值为整个表达式的值。
类型转换运算符
在 C++ 中,类型转换也相当复杂。不过不用担心,我们目前先学习较为简单的 C 风格类型转换。
运算符 | 名称 | 作用 |
---|---|---|
(type)a | C 风格转型运算符 | 将 a 的值转换为 type 类型 |
type(a) | 函数式转型运算符 |
表达式写法:
(类型标识)操作数 类型标识(操作数)
表达式的值就是转换为由 类型标识
指定的新类型的 操作数
的值。对于简单的类型,类型标识
就是之前说的类型标识符,如 int
unsigned
double
long long
等等。
例如:
这三个表达式的值分别为 double
类型的 42.0
, int
类型的 3
和 float
类型的 1.0
(想一想,为什么不是 1.666...
?)。
请注意,类型转换并不改变操作数的类型,而是根据操作数的值生成一个新类型的值。这里再次重申:在 C++ 中,一个已经声明并定义的变量的类型不会发生改变。
C 风格类型转换会尝试执行以下两种操作:
- 进行与隐式转换相同规则的转换(
static_cast
)。规则可参见隐式转换章节。- 进行指针重解释转换(
reinterpret_cast
),即转换指针的基类型。该操作被认为是有风险的。C 风格类型转换也可以同时移除变量只读性(通过指向只读变量的指针或者只读变量的引用)(
const_cast
)。该操作也被认为是有风险的。
类型转换表达式将要转换的类型明确地体现在代码中,因此这种类型转换成为显式类型转换(explicit cast)。而在 C++ 中类型转换有时又会自动发生(无需手动通过类型转换表达式发生),这些类型转换就是稍后我们会了解到的隐式类型转换。
优先级和结合方向
- C 风格转型运算符的优先级与前缀自增/减运算符相同,高于算术运算符。其结合方向为从右向左。
- 函数式转型运算符的优先级与后缀自增/减运算符相同。其结合方向为从左向右。函数式转型要求类型标识中不含空格、
&
和*
。
可以使用
using
或typedef
为类型指定别名来绕开此限制。
sizeof 运算符
sizeof 运算符用于查看一个操作数的类型所占的存储空间字节数。
运算符 | 名称 | 作用 |
---|---|---|
sizeof(a) | sizeof 运算符 | 查看 a 这个类型或值所占用的内存大小 |
sizeof 表达式的写法有两种,既可以直接写类型标识,也可以写一个操作数(变量、字面量或表达式):
sizeof(类型标识) sizeof 操作数
比如:
sizeof(int);
sizeof(42);
sizeof(char);
sizeof('@');
sizeof(long long);
sizeof(1000000000000ll);
// int[10] 是指拥有 10 个 int 的数组类型,如 `int a[10]{};` 中 a 的类型
sizeof(int[10]);
上述表达式的可能值分别为 4
, 4
, 1
, 1
, 8
, 8
, 40
。对于一个类型,这是这种类型的一个变量所占存储空间的字节数;对于一个操作数来说,这是存储这个操作数所需要的的存储空间的字节数。
sizeof 表达式的值在编译期间就会被确定,因此 sizeof 表达式无例外地都是常量。
这也侧面指出数组的长度必须是常量,否则数组类型 sizeof 表达式的值就不是常量了。
sizeof 表达式的值的类型为
std::size_t
。在某些编译器下,这个类型与unsigned int
等价。
优先级和结合方向
sizeof 运算符的优先级和前缀自增/减运算符相同。其结合性为从右向左。
尽管 sizeof 运算符查看操作数大小时不需要加括号,但建议加上括号以防止歧义。
如
sizeof (int) * p
这个表达式是有歧义的。