What & How & Why

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录前一修订版
后一修订版
前一修订版
cs:programming:cpp:courses:cpp_basic_deep:chpt_4 [2024/09/23 12:23] – [逻辑与关系操作符] codingharecs:programming:cpp:courses:cpp_basic_deep:chpt_4 [2024/10/03 06:03] (当前版本) – [sizeof] codinghare
行 135: 行 135:
 </code> </code>
 <WRAP center round info 100%> <WRAP center round info 100%>
-entity: unparenthesized id-expression or an unparenthesized class member access expression.+Entity**unparenthesized id-expression** or an **unparenthesized class member access expression**.
 </WRAP> </WRAP>
 ===类型转换=== ===类型转换===
行 269: 行 269:
     * 优先级:与高于或     * 优先级:与高于或
 ===位操作符=== ===位操作符===
 +  * ''~'': 按位取反,''|'':按位或,''&'':按位与,''^'' 按位异或
 +  * 接受右值,返回右值
 +  * 除取反,都是左结合
 +  * 计算过程中可能会存在整型提升
 +  * 不存在短路逻辑
 +<code cpp>
 +char x = 3; // 00000011
 +~x; // -4, 11111100
 +char y = 5; // 00000101
 +x & y; // 00000001
 +x | y; // 000000111
 +x ^ y; // 00000110 
 +</code>
 +==左移右移==
 +  * 缺出来的位置用 0 补全
 +  * 一定条件下可以替代乘/除 2,并且速度更快
 +<code cpp>
 +char x = 3; //00000011
 +x >> 1; // 00000001
 +char y = -4; // 11111100
 +// 与输出操作符合并使用时,需要使用括号进行重载
 +std::cout << (y << 1); // 11111000
 +</code>
 +==整型提升会根据符号位来填充==
 +<code cpp>
 +unsigned char x = 3;
 +// char 到 int 的提升
 +// unsigned 会按位进行 0 的补全
 +unsigned char z = 0xff // 11111111
 +// 0000...00011111111 总共32位
 +auto y = ~x; // 结果为 256
  
 +//signed 的提升会按照符号位来进行补全的提升,这里是 1 
 +signed char z = 3; 
 +// 提升过后的值为 11111......111111 
 +// 求反后的结果是 00000....000000 
 +y = ~z; // 结果是 0 
 +</code> 
 +===赋值操作符=== 
 +  * 赋值操作符左边为**可修改的**左值,右边为可转换为左边类型的右值。 
 +  * 赋值操作符为右结合(先评估等号右边) 
 +  * 求值结果为左算子 
 +  * 可以引入大括号防止 narrowing converstion 
 +<code cpp> 
 +short x; 
 +// error, can't store a unsigned int to short 
 +x = {0x80000003}; 
 +// 无精度损失的转换不会被阻止 
 +x = {3}; 
 +// 只要存在 norrowing conversion 的可能,编译器就不会通过 
 +// y 可能会被修改导致 norrowing conversion 
 +int y = 3; 
 +x = {y}; 
 +// 使用编译器期 const 确保 y 不会被修改 
 +constexpr int y = 3; 
 +x = {y}; 
 +</code> 
 +  * 赋值操作符的优先级非常低 
 +==交换两个数== 
 +<code cpp> 
 +// bitwise xor 
 +int x = 2; 
 +int y = 3; 
 +// x = 2^3 | y = 3 
 +x^=y; 
 +// 任何数与 0 xor 结果都是其本身 
 +// x = 2^3 | y = 3^2^3 = 2^3^3 = 2^0 = 2 
 +y^=x; 
 +// x =2^3^2 = 3 | y = 2 
 +x^=y; // 最后结果 x = 3, y =2 
 +</code> 
 +===自增 / 自减操作符=== 
 +  * 后缀 ''i++'':返回 ''i'' (的原始值),再自增 
 +  * 前缀 ''++i'':自增,再返回 ''i'' (运算之后的)值 
 +  * 前缀返回**左值**,后缀返回**右值** 
 +<WRAP center round box 100%> 
 +  * 后缀在返回的时候当前变量已经更新,因此只能返回一个历史内容,属于临时变量,因此是右值 
 +  * 前缀可以视作 x = x + 1; 得到是左值。该左值还可以接着放到等号左边,因此 ++(++x) 也是合法的。 
 +  * 推荐使用前缀:后缀会创造**临时变量**并返回,效率较低。 
 +  * 后缀一般用于需要利用返回值的时候,比如运算符重载时(类)可能会用到 
 +</WRAP> 
 +===其他操作符=== 
 +==成员访问操作符== 
 +  * ''.'' 成员访问操作符 
 +  * 实质是 ''->'' 通过(this)指针访问成员 
 +<code cpp> 
 +struct Str { int x }; 
 +int main() 
 +
 +    Str a; 
 +    // a 是左值,返回左值 
 +    a.x; 
 +    // Str() 是 右值, 返回值为右值引用 
 +    Str().x; 
 +    //(*ptr).x,返回左值 
 +    ptr->x; 
 +
 +</code> 
 +==三元条件操作符== 
 +<code cpp> 
 +// 只会求值一个分支 
 +true ? 3:5; 
 +// 条件表达式返回的类型必须相同 
 +ture ? 1: "hello"; // error 
 +// 都是左值,则返回左值,否则返回右值 
 +int x = 0; 
 +false ? 1 : x; // 返回右值 
 +// 右结合 
 +// 先判断 score == 0 
 +int score = 100; 
 +int res = (score > 0) ? 1: (score == 0) ? 0:-1; 
 +</code> 
 +==逗号操作符== 
 +  * 典型应用: 
 +    * for 循环中可以写出较为复杂的语句 
 +    * 元编程:折叠表达式,包展开 
 +  * 函数的参数表达式不是逗号操作符,参数列表求值顺序不定 
 +<code cpp> 
 +// 确保操作数从左向右求值 
 +// 求值结果为右算子 
 +2, 3; // result is 3 
 +// 左结合 
 +// (2, 3) , 4 
 +2, 3, 4; 
 +</code> 
 +==sizeof== 
 +  * 返回类型 / 对象 / 表达式返回值占用的字节数 
 +<code cpp> 
 +int x; 
 +// 推荐统一使用带括号的形式 
 +sizeof(int); 
 +sizeof(x); 
 +// 对表达式评估时,不会真正执行求值 
 +int* ptr = nullptr; 
 +// 等价 sizeof(int) 
 +sizeof(*ptr); 
 +</code> 
 +==域操作符== 
 +用于访问域内的变量 
 +<code cpp> 
 +int = x; 
 +namspace ABC 
 +
 +   int x; 
 +
 +int main() 
 +
 +   int x; 
 +   int y = x; // local 
 +   int y = ::x; // global 
 +   int y = ABC::x // ABC 
 +
 +</code> 
 +===C++17表达式求值顺序=== 
 +  * 之前的限定求值:逗号,三元条件,逻辑与 / 或(短路) 
 +  * C++17 新引入的限定 
 +<code cpp> 
 +// 先求 e1,再求 e2 
 +e1[e2]; 
 +e1.e2; 
 +e1.*e2; 
 +e1->*e2; 
 +e1<<e2; 
 +e1>>e2; 
 +e2=e1 / e2+=e1/ e2*=e1; 
 +</code> 
 +   * newType(e) 会先分配内存再求值