表达式

本章摘录要点并给出准确表述与示例,便于复习。注意:现代 C++(自 C++11 起)对求值顺序有更精细的规定,但单个表达式中既修改又使用同一对象仍应避免未定义行为。

4.1 求值顺序与未定义行为

  • 如果在同一表达式中对同一对象既有修改操作又有未被序列化(sequenced)使用,可能导致未定义行为。示例(不要写成这样):
cout << i << i++ << endl; // 未定义(依赖于求值顺序)

更安全的写法是将修改和读取分开为不同语句。

4.2 算术运算符与常见注意点

  • 加、减、乘、除、取模等。除法在整数间是整数除法。注意溢出和除以 0。

4.3 关系运算符(与空指针检查)

示例:既要判空又要判非空字符串时常见写法:

void test03() {
    const char *cp = "hello world";
    if (cp && *cp) // cp 非空且首字符非 '\0'
        cout << cp << '\n';
}

4.4 赋值运算符

  • 赋值运算符的优先级通常低于关系运算符,因此 if (a = b) 会先执行赋值再判断结果是否为零,请谨慎使用。

4.5 递增和递减运算符

  • 前置(++i)返回已递增后的左值,后置(i++)返回递增前的值(作为右值);对用户自定义类型而言,前置通常更高效。

示例说明:

cout << *iter++ << '\n'; // 等价于: cout << *iter; ++iter;  (先解引用,再将迭代器后移)

4.6 成员访问与求值顺序

  • 当一个子表达式会修改对象而另一个子表达式使用该对象时,求值顺序决定行为是否定义。建议避免在单个表达式中同时修改并使用同一对象。

4.7 条件(三元)运算符 ?:

  • 三元运算符等价于简短的 if-else,可嵌套使用,但为了可读性,深度嵌套应避免。

示例:

std::string finalgrade = (grade > 90) ? "highGrade" : (grade < 60) ? "fail" : "pass";

4.8 位运算符

  • 常见位运算:&(按位与)、|(按位或)、^(按位异或)、~(按位取反)、<<(左移)、>>(右移)。
  • 移位运算的优先级介于算术与关系运算之间;注意对符号位的影响以及移位超过类型位宽会产生未定义行为。

4.9 sizeof 运算符

  • sizeof 在编译期通常产生常量表达式(对动态大小数组的例外除外)。对数组使用 sizeof 可得到整个数组大小(字节数),不是元素个数。

示例:

int b[10];
size_t bytes = sizeof(b);            // 10 * sizeof(int)
size_t elems = sizeof(b) / sizeof(b[0]);

4.10 逗号运算符

  • 逗号运算符从左到右求值,丢弃左侧结果,返回最右侧表达式的值,常用于较低层面的表达式组合;不要与逗号分隔符混淆(函数参数、初始化列表使用的逗号)。

示例:

int x = (f(), g()); // 会先调用 f(),然后调用 g(),x 取 g() 的返回值

4.11 类型转换(概述)

  • 常见规则:整型提升(promotions)、算术转换(usual arithmetic conversions)、以及显式转换(static_cast, reinterpret_cast, const_cast)。
  • 布尔上下文中会将非布尔值转换为 bool(0 -> false,非 0 -> true)。

简要示例:

int a = 3; unsigned int b = 5u;
auto r = a + b; // usual arithmetic conversions: int -> unsigned int (可能导致符号相关行为)

double d = static_cast<double>(a) / 2; // 更明确的浮点除法

©OZY all right reserved该文件修订时间: 2025-09-20 05:42:10

评论区 - 11_Expressions

results matching ""

    No results matching ""