Cpp学习8 第 6 章 运算符

铁名_IronName Lv5

6.1 — 运算符优先级和结合性

运算是指涉及零个或多个输入值(称为操作数 )并产生新值(称为输出值)的数学过程。要执行的具体运算由称为运算符的结构(通常是一个符号或一对符号)表示。

略。常用的大家都知道。不常用分不清的,加个括号也都看得懂了。
一条好的经验法则是:除了加法、减法、乘法和除法之外,所有运算都要用括号括起来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>

int getValue()
{
std::cout << "Enter an integer: ";

int x{};
std::cin >> x;
return x;
}

void printCalculation(int x, int y, int z)
{
std::cout << x + (y * z);
}

int main()
{
printCalculation(getValue(), getValue(), getValue()); // this line is ambiguous

return 0;
}

如果你运行这个程序并输入 1 和 2 ,你可能会认为这个程序会计算 1 + (2 * 3) 并输出 7 但这假设 printCalculation 3 printCalculation() 函数的参数会按从左到右的顺序计算(即参数 x 值为 1 , y 值为 2 , z 值为 3 )。如果参数按从右到左的顺序计算(即参数 z 值为 1 , y 值为 2 , x 值为 3 ),那么程序会输出 5 。(这取决于编译器)
通过将每次对 getValue() 函数的调用都写成单独的语句,可以消除上述程序的歧义:

1
2
3
4
5
int a{ getValue() }; // will execute first
int b{ getValue() }; // will execute second
int c{ getValue() }; // will execute third

printCalculation(a, b, c); // this line is now unambiguous
警告

确保你编写的表达式(或函数调用)不依赖于操作数(或参数)的求值顺序。

6.2 — 算术运算符

如果任一操作数是浮点数,则结果将是浮点数除法,而不是整数除法。
An operator that can modify the value of one of its operands is informally called a modifying operator.修改运算符。

6.3 — 余数和指数运算

取余运算符 (也常被称为取模运算符 )用于返回整数除法运算后的余数。

余数运算符也可以处理负数操作数。x % y 总是返回与 x 符号相同的结果。
-6 % 4 = -2;6 % -4 = 2

如果要比较取余运算的结果,最好与 0 进行比较,因为 0 不存在正负数的问题

指数运算符在哪里?

C++ 本身并不包含指数运算符。
要在 C++ 中进行指数运算,请包含以下头文件:<cmath>,使用 pow() 函数。
如果你想进行整数幂运算,最好使用自定义函数。

6.4 — 递增/递减运算符及其副作用

++x 前缀递增/递减运算符非常简单明了。首先,操作数递增或递减,然后表达式的值等于操作数的值。
后缀递增/递减运算符比较复杂。首先,复制操作数。然后,递增或递减操作数本身(而不是副本)。最后,计算的是副本(而不是原始操作数)的值。
后缀版本需要更多步骤,因此其性能可能不如前缀版本。

最佳实践

尽量使用前缀版本,因为它们性能更高,而且不太可能出现意外情况。

警告

不要在同一语句中多次使用带有副作用的变量。否则,结果可能是未定义的。比如 x + ++x
一个例外是简单的赋值表达式,例如 x = x + y (这本质上等价于 x += y )。

6.5 — 逗号运算符

逗号运算符 (,) comma operator 允许您在只能使用单个表达式的地方计算多个表达式。逗号运算符会先计算左操作数,再计算右操作数,然后返回右操作数的结果。

大多数程序员根本不使用逗号运算符,唯一的例外是在 for 循环 内部,在那里逗号运算符的使用相当普遍。除了在 for 循环 中,应避免使用逗号运算符。

6.6 — 条件运算符

三目运算符,if-else压缩版

1
2
3
4
if (x > y)
max = x;
else
max = y;

可以改写为:

1
max = ((x > y) ? x : y);

为避免此类评估优先级问题,条件运算符应按如下方式用括号括起来

1
2
3
4
return isStunned ? 0 : movesLeft;           // not used in compound expression, condition contains no operators
int z { (x > y) ? x : y }; // not used in compound expression, condition contains operators
std::cout << (isAfternoon() ? "PM" : "AM"); // used in compound expression, condition contains no operators (function call operator excluded)
std::cout << ((x > y) ? x : y); // used in compound expression, condition contains operators

在复杂的表达式中,尽量避免使用条件运算符。因为它们容易出错且难以阅读。

6.7 — 关系运算符和浮点数比较

关系运算符是用于比较两个值的运算符。每个运算符的计算结果均为布尔值,true (1) 或false (0)。

警告

如果浮点值有可能是计算出来的,请避免使用运算符==和运算符!=来比较浮点值。

比较不同类型的浮点字面量通常是不安全的。

判断浮点数相等的最常用方法是使用一个函数来判断两个数是否“ 足够 接近”。如果它们“足够接近”,我们就认为它们相等。用来表示“足够接近”的值通常称为 ε。ε 通常被定义为一个很小的正数(例如 0.00000001,有时也写作 1e-8)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <algorithm> // for std::max
#include <cmath> // for std::abs
#include <iostream>

// Return true if the difference between a and b is within epsilon percent of the larger of a and b
bool approximatelyEqualRel(double a, double b, double relEpsilon)
{
return (std::abs(a - b) <= (std::max(std::abs(a), std::abs(b)) * relEpsilon));
}

// Return true if the difference between a and b is less than or equal to absEpsilon, or within relEpsilon percent of the larger of a and b
bool approximatelyEqualAbsRel(double a, double b, double absEpsilon, double relEpsilon)
{
// Check if the numbers are really close -- needed when comparing numbers near zero.
if (std::abs(a - b) <= absEpsilon)
return true;

// Otherwise fall back to Knuth's algorithm
return approximatelyEqualRel(a, b, relEpsilon);
}

int main()
{
// a is really close to 1.0, but has rounding errors
constexpr double a{ 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 };

constexpr double relEps { 1e-8 };
constexpr double absEps { 1e-12 };

std::cout << std::boolalpha; // print true or false instead of 1 or 0

std::cout << approximatelyEqualRel(a, 1.0, relEps) << '\n'; // compare "almost 1.0" to 1.0
std::cout << approximatelyEqualRel(a-1.0, 0.0, relEps) << '\n'; // compare "almost 0.0" to 0.0

std::cout << approximatelyEqualAbsRel(a, 1.0, absEps, relEps) << '\n'; // compare "almost 1.0" to 1.0
std::cout << approximatelyEqualAbsRel(a-1.0, 0.0, absEps, relEps) << '\n'; // compare "almost 0.0" to 0.0

return 0;
}

可以看出,appreadlyEqualAbsRel() 函数能够正确处理较小的输入值。
浮点数的比较是一个复杂的问题,没有一种“万能”算法可以适用于所有情况。但是,使用绝对值 ε = 1e-12、相对值 ε = 1e-8 的 approximateEqualAbsRel() 函数应该足以应对您遇到的大多数情况。

6.8 — 逻辑运算符

! && ||
为了使_逻辑与运算_返回真,两个操作数都必须为真。如果左操作数为假, 逻辑与运算 知道无论右操作数为真还是假,它都必须返回假。在这种情况下, 逻辑与 运算符会立即返回假,甚至不会计算右操作数!这被称为短路求值 ,它主要用于优化性能。

警告

短路求值可能导致 逻辑或 (Logicor) 和 逻辑与 (Logical AND) 运算无法正确计算操作数。请避免将这些运算符与带有副作用的表达式一起使用。

当操作数为 bool 时, operator!= 产生的结果与逻辑异或 XOR 相同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <string>
#include <string_view>

std::string_view getQuantityPhrase(int appleNum)
{

if (appleNum < 0)
return static_cast<std::string_view>("negative");
if (appleNum == 0)
return "no";
if (appleNum == 1)
return "a single";
if (appleNum == 2)
return "a couple of";
if (appleNum == 3)
return "a few";

return "many";
}

std::string_view getApplesPluralized(int appleNum)
{
if (appleNum == 1)
return "apple";
else
return "apples";
}

int main()
{
constexpr int maryApples{ 3 };
std::cout << "Mary has " << getQuantityPhrase(maryApples) << ' ' << getApplesPluralized(maryApples) << ".\n";

std::cout << "How many apples do you have? ";
int numApples{};
std::cin >> numApples;

std::cout << "You have " << getQuantityPhrase(numApples) << ' ' << getApplesPluralized(numApples) << ".\n";

return 0;
}
  • 标题: Cpp学习8 第 6 章 运算符
  • 作者: 铁名_IronName
  • 创建于 : 2026-08-08 13:38:09
  • 更新于 : 2026-08-08 14:48:41
  • 链接: https://blog.ironname.top/2026/Cpp/Cpp学习8/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论