赋值运算符
赋值运算符为变量赋值,此语句将整数值分配给变量 。赋值操作始终从右到左进行,例如x = 4
算术运算符 ( +, -, *, /, % )
加法
减法
乘法
除法
模运算符,用百分号 () 表示,给出两个值的除法的余数
复合赋值(+=、-=、*=、/=、%=、>>=、<<=、&=、^=、|=)
复合赋值运算符通过对变量执行操作来修改变量的当前值。它们等效于将运算结果分配给第一个操作数,
例如
y+= x 与 y = y + x,剩下以此类推
递增和递减 (++, --)
递增(++)和递减(--)运算符用于增加或减少变量的值。这两种运算符都有前缀和后缀形式,它们的主要区别在于操作的执行顺序和返回的值
有些表达式可以进一步缩短:增加运算符 () 和减少运算符 () 将存储在变量中的值增加或减少 1
在功能上都是等效的;它们中的三个将 x的值增加 1 | |
在功能上都是等效的;它们中的三个将 的值增加 1
-
前缀形式:
++variable
:前缀递增运算符会先增加变量的值,然后再使用新的值进行计算。--variable
:前缀递减运算符会先减少变量的值,然后再使用新的值进行计算。
-
后缀形式:
variable++
:后缀递增运算符会先使用变量的当前值进行计算,然后才增加变量的值。variable--
:后缀递减运算符会先使用变量的当前值进行计算,然后才减少变量的值。
示例代码:
#include <stdio.h>
int main()
{
int a = 8 ;
// 后缀递增
int b = a++;
//前缀递增
int c = ++a;
//后缀递减
int d = a--;
//前缀递减
int f = --a;
printf("%d\n", b);
printf("%d\n", c);
printf("%d\n", d);
printf("%d\n", f);
return 0;
}
关系运算符和比较运算符 ( ==, !=, >, <, >=, <= )
可以使用关系运算符和相等运算符比较两个表达式。例如,要知道两个值是否相等,或者一个值是否大于另一个值。此类操作的结果为 true 或 false(即布尔值
算子 | 描述 |
---|---|
== | 等于 |
!= | 不等于 |
< | 小于 |
> | 大于 |
<= | 小于或等于 |
>= | 大于或等于 |
例子:
(5 == 5) // true
(5 > 4) // true
(8 != 9) // true
(10 >= 10) // true
(7 < 3) // false
- 可以比较的不仅仅是数值常量,而是任何值,当然也包括变量
逻辑运算符 ( !, &&, | |)
逻辑非 (!)
对一个表达式的值进行否定,如果它的操作数是 ,如果它的操作数是 。基本上,它返回计算其操作数的相反布尔值。其中0 代表假,非0 代表真
示例代码:
#include <stdio.h>
int main()
{
int a = 1;
int b = 0;
// 逻辑非
int c = !a; // c 的值为 0,因为 a 非零,所以 !a 为假
printf("%d\n",c);
return 0;
}
逻辑与 (&&)
- 对两个表达式进行逻辑与操作。
- 如果两个表达式的值都为非0(真),则
&&
运算后的结果为1(真)。 - 否则,如果任意一个表达式的值为0(假),则整个
&&
运算的结果为0(假) -
以下面板显示了运算符计算表达式的结果
&& OPERATOR(和) | ||
---|---|---|
a | b | a && b |
true | true | true |
true | false | false |
false | true | false |
false | false | fase |
短路行为:当左侧表达式的值为0(假)时,由于无论右侧表达式的值如何,整个 &&
运算的结果都已经确定为0(假),所以编译器可能会优化代码,不再评估右侧的表达式
逻辑或 (||)
- 对两个表达式进行逻辑或操作。
- 如果两个表达式中任意一个的值为非0(真),则
||
运算后的结果为1(真)。 - 否则,如果两个表达式的值都为0(假),则整个
||
运算的结果为0(假)
||运算符(或) | ||
---|---|---|
a | b | a || b |
true | true | true |
true | false | true |
false | true | true |
false | false | false |
- 短路行为:当左侧表达式的值为非0(真)时,由于无论右侧表达式的值如何,整个
||
运算的结果都已经确定为1(真),所以编译器可能会优化代码,不再评估右侧的表达式。
条件三元运算符 ( ? )
条件运算符计算表达式,如果该表达式的计算结果为 ,则返回一个值,如果表达式的计算结果为 ,则返回另一个值
基本语法:condition ? value_if_true : value_if_false;
示例代码:
#include <stdio.h>
int main()
{
int a, b, c;
a = 2;
b = 7;
c = (a > b) ? a : b;
printf("%d\n", c);
}
注意:在实际编程中,为了提高可读性,对于多个条件的情况,通常会使用 if-else 语句而不是连续的三元运算符
逗号运算符 ( , )
逗号运算符 () 用于分隔两个或多个表达式,这些表达式仅应包含一个表达式。当必须计算表达式集的值时,仅考虑最右边的表达式。
例如a = (b=3, b+2);
按位运算符 ( &, |, ^, ~, <<, >> )
按位运算符修改变量时,会考虑表示它们存储的值的位模式。
算子 | ASM 等效项 | 描述 |
---|---|---|
& | AND | 按位 AND |
| | OR | 按位包含 OR |
^ | XOR | 按位独占 OR |
~ | NOT | 一元补码(位反转) |
<< | SHL | 向左移动位 |
>> | SHR | 向右移动位 |
显式类型转换运算符
在C++中,有四种显式类型转换运算符用于执行特定类型的强制转换:
-
static_cast:
- 用于在编译时可确定的类型之间进行转换,如基本数据类型(int、float、double等)之间的转换,或指针类型和引用类型之间的转换。
- 可以用于非多态类型的转换,但如果尝试向下转换一个基类指针或引用到不相关的派生类,结果是未定义的。
- 示例:
int i = 10; float f = static_cast<float>(i);
-
dynamic_cast:
- 主要用于运行时的类型检查和转换,特别是对于多态类型(包含虚函数的类)的转换。
- 当试图将基类指针或引用转换为派生类时,如果实际对象不是目标类型或者是指向null的指针,dynamic_cast会返回nullptr(对于指针)或抛出bad_cast异常(对于引用)。
- 示例:
Base* basePtr = new Derived(); Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);
-
const_cast:
- 用于修改类型的const、volatile或__unaligned属性,但不能改变对象的实际类型。
- 主要用于去除const限制,以便对原本为const的对象进行修改。但是,如果对象实际上是常量或者被定义为const,那么试图修改其内容会导致未定义的行为。
- 示例:
const int ci = 10; int& i = const_cast<int&>(ci); // 尽管去除了const,但修改i仍然是未定义行为
-
reinterpret_cast:
- 用于底层的比特模式转换,通常用于不同类型之间的转换,如将指针转换为整数或反过来转换。
- 这种转换非常危险,因为它们忽视了类型的安全性,可能导致未定义的行为或数据损坏。
- 示例:
int* ip = reinterpret_cast<int*>(some_char_ptr); // 风险操作,将字符指针转换为整数指针
sizeof
此运算符接受一个参数,该参数可以是类型或变量,并返回该类型或对象的大小(以字节为单位)
x = sizeof (char);这里,被赋值 ,因为是一个大小为一个字节的类型。返回的值是编译时常量,因此它始终在程序执行之前确定
1.计算基本数据类型的大小
示例代码:
#include <stdio.h>
int main()
{
int a;
printf("Size of int: %zu bytes\n", sizeof(int));
}
2.计算变量的大小:
示例代码:
#include <stdio.h>
int main()
{
double c;
printf("Size of double variable 'c': %zu bytes\n", sizeof(c));
}
3.计算数组的大小(注意:结果是整个数组的大小,而不是元素的数量):
示例代码:
#include <stdio.h>
int main()
{
int array[10];
printf("Size of int array 'array': %zu bytes\n", sizeof(array));
}
4.计算结构体或类的大小:
示例代码:
#include <stdio.h>
int main()
{
struct MyStruct {
int a;
char b;
double c;
};
MyStruct myStruct;
printf("Size of MyStruct: %zu bytes\n", sizeof(myStruct));
}
注意的是,sizeof
不会计算动态分配内存的大小,例如通过 malloc
或 new
分配的内存。此外,对于指针变量,sizeof
返回的是指针本身的大小,而不是指针所指向的数据的大小
运算符的优先级
水平 | 优先级组 | 算子 | 描述 | 分组 |
---|---|---|---|---|
1 | 范围 | :: | 范围限定符 | 从左到右 |
2 | 后缀(一元) | ++ -- | 后缀递增/递减 | 从左到右 |
() | 功能形式 | |||
[] | 下标 | |||
. -> | 会员访问 | |||
3 | 前缀(一元) | ++ -- | 前缀递增/递减 | 从右到左 |
~ ! | 按位 NOT / 逻辑 NOT | |||
+ - | 一元前缀 | |||
& * | 引用/取消引用 | |||
new delete | 分配/取消分配 | |||
sizeof | 参数包 | |||
(type) | C型铸造 | |||
4 | 指向成员的指针 | .* ->* | 访问指针 | 从左到右 |
5 | 算术:缩放 | * / % | 乘法、除法、取模 | 从左到右 |
6 | 算术:加法 | + - | 加法、减法 | 从左到右 |
7 | 按位移位 | << >> | 左移,右移 | 从左到右 |
8 | 关系 | < > <= >= | 比较运算符 | 从左到右 |
9 | 平等 | == != | 平等/不平等 | 从左到右 |
10 | 和 | & | 按位 AND | 从左到右 |
11 | 排他性或 | ^ | 按位异或 | 从左到右 |
12 | 包含或 | | | 按位 OR | 从左到右 |
13 | 连接 | && | logical 和 | 从左到右 |
14 | 分离 | || | 逻辑 OR | 从左到右 |
15 | 赋值级表达式 | = *= /= %= += -= | 赋值/复合赋值 | 从右到左 |
?: | 条件运算符 | |||
16 | 测 序 | , | 逗号分隔符 | 从左到右 |