C++ 运算符

算术运算符

运算符

术语

示例

结果

+

10 + 5

15

-

10 - 5

5

*

10 * 5

50

/

10 / 5

2

%

取模(取余)

10 % 3

1

++

前自增

a=2; b=++a;

a=3; b=3;

++

后自增

a=2; b=a++;

a=3; b=2;

--

前自减

a=2; b=--a;

a=1; b=1;

--

后自减

a=2; b=a--;

a=1; b=2;

示例代码:

#include <stdio.h>

int main() {
    // 2数相除,要想得到小数的结果,分子分母必须有一个数是小数
    double c = 5/2; // 5, 2个都是整数,只会取整
    printf("c1 = %lf\n", c);

    c = 5.0/2; 
    printf("c2 = %lf\n", c);

    c = 5/2.0; 
    printf("c3 = %lf\n", c);

    int i = 0;
    // 前置++
    // 先加后用
    int b = ++i; 
    printf("前置:b = %d, i = %d\n", b, i);

    // 后置++
    // 先用后加
    i = 0;
    b = i++;
    printf("后置:b = %d, i = %d\n", b, i);

    return 0;
}

运行结果:

c1 = 2.000000
c2 = 2.500000
c3 = 2.500000
前置:b = 1, i = 1
后置:b = 0, i = 1

赋值运算符

运算符

术语

示例

结果

=

赋值

a=2; b=3;

a=2; b=3;

+=

加等于

a=0; a+=2;

等同于 a = a + 2;

a=2;

-=

减等于

a=5; a-=3;

等同于 a = a - 3;

a=2;

*=

乘等于

a=2; a*=2;

等同于 a = a * 2;

a=4;

/=

除等于

a=4; a/=2;

等同于 a = a / 2;

a=2;

%=

模等于

a=3; a%=2;

等同于 a = a % 2;

a=1;

示例代码:

#include <stdio.h>

int main() {
    int a = 10;
    a += 5;
    printf("a = %d\n", a);

    return 0;
}

运行结果:

a = 15

比较运算符

C 语言的比较运算中, “真”用数字“1”来表示, “假”用数字“0”来表示。

运算符

术语

示例

结果

==

相等于

4 == 3

0

!=

不等于

4 != 3

1

<

小于

4 < 3

0

>

大于

4 > 3

1

<=

小于等于

4 <= 3

0

>=

大于等于

4 >= 1

1

示例代码:

#include <stdio.h>

int main() {
    int a = 10;
    int b = 20;
    printf("%d\n", a == b);
    printf("%d\n", a != b);
    printf("%d\n", a > b);
    printf("%d\n", a < b);
    printf("%d\n", a >= b);
    printf("%d\n", a <= b);

    return 0;
}

逻辑运算符

运算符

术语

示例

结果

!

!a

如果a为假,则!a为真;

如果a为真,则!a为假。

&&

a && b

如果a和b都为真,则结果为真,否则为假。

||

a || b

如果a和b有一个为真,则结果为真,二者都为假时,结果为假。

示例代码:

#include <stdio.h>

int main() {

    // &&(与),可以理解为并且
    // 案例:请判断班长和他女朋友是否符合法定结婚年龄
    int boy = 25;
    int girl = 21;
    int result = boy >= 22 && girl >= 20;
    printf("%d\n", result);

    // ||(或),可以理解为或者
    // 案例:班长女朋友玩原神没有原石了,请帮班长判断是否有足够的钱
    double wx_money = 100;
    double alipay_money = 300;
    result = wx_money >= 398 || alipay_money >= 398 || wx_money+alipay_money >= 398;
    printf("%d\n", result);
    
    // !(非),可以理解为不是
    printf("%d\n", !0);
    printf("%d\n", !!1);

    // 短路规则
    // && 左边为假,右边不执行
    0 && printf("我是右边\n");
    // || 左边为真,右边不执行
    1 || printf("我是右边\n");
    
    return 0;
}

位运算符

常见的位运算符号有&、|、^、~、>>、<<,分别代表着如下含义:

运算符

术语

示例

结果

&

按位与运算

011 & 101

2个都为1才为1,结果为001

|

按位或运算

011 | 101

有1个为1就为1,结果为111

^

按位异或运算

011 ^ 101

不同的为1,结果为110

~

取反运算

~011

100

<<

左移运算

1010 << 1

10100

>>

右移运算

1010 >> 1

0101

ps:取反、左右位移运算需要在补码的基础上运算。

& -(与运算)

按位与(&)运算:位与位进行比较,如果都为1,则为1,否则为0;

/**
     * 按位与(&)运算:位与位进行比较,如果都为1,则为1,否则为0;
     * 示例:
     *          40    &     15    =     8
     *      0010 1000 
     *    & 0000 1111 
     * -------------------
     *      0000 1000
     */
printf("40 & 15 = %d\n", 40 & 15);

| -(或运算)

按位或(|)运算:位与位进行比较,如果都为0,则为0,否则为1;

/**
     * 按位或(|)运算:位与位进行比较,如果都为0,则为0,否则为1;
     * 示例:
     *          40    |     15    =     47
     *      0010 1000 
     *    | 0000 1111
     * ----------------
     *      0010 1111
     */
printf("40 | 15 = %d\n", 40 | 15);

^ -(异或运算)

按位异或运算:位与位进行比较,相同为0,不同为1;

/**
     * 按位异或运算:位与位进行比较,相同为0,不同为1;
     * 示例:
     *          40    ^     15    =     39
     *      0010 1000 
     *    ^ 0000 1111 
     * ------------------
     *      0010 0111
     */
printf("40 ^ 15 = %d\n", 40 ^ 15);

~ -(取反运算)

按位取反运算:补码取反,再将取反后的补码转为原码;

ps:无符号的数据,取反后最高位为1,也不需要逆运算。

/**
 * 按位取反运算:补码取反,再将取反后的补码转为原码。
 *      1、正数取反:由于正数的原码和补码是相同的,取反的方式简便了些。
 *              补码(原码) -> 取反 -> 补码逆运算 -> 反码逆运算(符号位不变) -> 取反后的原码
 *      2、负数取反:
 *              原码 -> 反码 -> 补码 -> 取反 -> 取反后的补码即原码
 * 示例:
 *            原码(补码)  取反的补码   补码逆运算-1  反码逆运算
 *      ~40 = 0010 1000 -> 1101 0111 -> 1101 0110 -> 1010 1001 = -41
 *
 *            原码(补码)  取反的补码   补码逆运算-1  反码逆运算
 *      ~15 = 0000 1111 -> 1111 0000 -> 1110 1111 -> 1001 0000 = -16
 *
 *                原码         反码          补码          取反
 *      ~-15 = 1000 1111 -> 1111 0000 -> 1111 0001 -> 0000 1110 = 14
 */
printf("~40 = %d\n", ~40);
printf("~15 = %d\n", ~15);
printf("~-15 = %d\n", ~(-15));

<< -(左移运算符)

将数字的二进制补码全部向左移动,空出来的位置补0,超出范围的二进制数丢弃

有符号的数据左移后最高位如果为1,则需要进行逆运算;

注意事项:

  • 无符号的数据,左移后最高位为1,也不需要逆运算;
  • -128:1000 0000 特殊情况也不需要逆运算;
/**
     * 示例:
     *      40 << 4 = 0010 1000 << 4 = 1000 0000 = -128 (特殊的不需要逆运算)
     *      41 << 4 = 0010 1001 << 4 = 1001 0000 = 1000 1111 = 1111 0000 = -112
     *       7 6 5 4 3 2 1 0
     *       1 0 0 1 0 0 0 0
     */

    int8_t p = 40;
    p <<= 4;    //  p = p << 4;
    printf("40 << 4 = %d\n", p);

>> -(右移运算符)

将数字的二进制补码全部向右移动,空出来的位置补什么,取决于原来的最高位是什么。原来的最高是1就补1, 原来的最高位是0 就补0 。也可以转化成这样的一句话: 正数补0, 负数补1;

	
	/*
	  23: 0001 0111【原码】 ----  0001 0111【反码】 ----  0001 0111 【补码】
											  >> 2
	  -----------------------------------------------
										  0000 0101【补码】 --->  5
	 */
	printf(" 23 >> 2 = %d \n" , 23 >> 2) ; 
	
	
	/*
	  123: 1001 0111【原码】 ----  1110 1000【反码】----  1110 1001【补码】
											  >> 2
	  -----------------------------------------------
											1111 1010【补码】 --->  1111 1001【反码】- ----- 1000 0110 【原码】===> -6
	 */
	printf(" -23 >> 2 = %d \n" , -23 >> 2) ; 

示例代码:

#include <stdio.h>
#include <inttypes.h>

int main() {
    uint8_t a = 3;          // 0000 0011
    uint8_t b = 10;         // 0000 1010
    // 打印显示2个字符,个数不够,左边补0
    printf("%02x\n", a & b); // 0000 0010,16进制为02
    printf("%02x\n", a | b); // 0000 1011,16进制为0b
    printf("%02x\n", a ^ b); // 0000 1001,16进制为09

    uint8_t c = 10;          // 0000 1010
    uint8_t temp = ~c;       // 1111 0101
    printf("%02x\n", temp);   // 1111 0101,16进制为f5
    printf("%02x\n", c << 1); // 0001 0100,16进制为14
    printf("%02x\n", c >> 1); // 0000 0101,16进制为05

    return 0;
}

运行结果:

02
0b
09
f5
14
05

案例需求:

// 将变量a的第2位设置为1,其他位保持不变
uint8_t a = 0b10110011; // 0xb3;

// 将变量b的第2位、第6位设置为1,其他位保持不变
uint8_t b = 0b10110011; // 0xb3;

// 将变量c的第5位设置为0,其他位保持不变
uint8_t c = 0b10110011;  // 0xb3;

// 将变量d的第0~3位设置为0,其他位保持不变
uint8_t d = 0b11111111;  // 0xff;

// 将变量e的第2位取反,其他位保持不变
uint8_t e = 0b10110011;  // 0xb3;

// 将变量f取出8-15位
uint32_t f = 0x12345678;

示例代码:

#include <stdio.h>
#include <inttypes.h>

int main() {
    // 将变量a的第2位设置为1,其他位保持不变
    uint8_t a = 0b10110011; // 0xb3;
    a |= (1 << 2);          // 或者 x = x | (1 << 2);
    printf("%02x\n", a);    // b7,  10110111

    // 将变量b的第2位、第6位设置为1,其他位保持不变
    uint8_t b = 0b10110011; // 0xb3;
    b |= (1 << 2 | 1 << 6);
    printf("%02x\n", b);    // f7,11110111

    // 将变量c的第5位设置为0,其他位保持不变
    uint8_t c = 0b10110011;  // 0xb3;
    c &= ~(1 << 5);
    printf("%02x\n", c);    // 93,10010011

    // 将变量d的第0~3位设置为0,其他位保持不变
    uint8_t d = 0b11111111;  // 0xff;
    d &= ~(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3);
    printf("%02x\n", d);    // f0,11110000

    // 将变量e的第2位取反,其他位保持不变
    uint8_t e = 0b10110011;  // 0xb3;
    e ^= (1 << 2);
    printf("%02x\n", e);    // b7,  10110111

    // 将变量f取出8-15位
    uint32_t f = 0x12345678;
    uint32_t temp = (f & 0x0000ff00) >> 8;
    printf("%#x\n", temp);

    return 0;
}

运算符优先级

  • 不同的运算符默认具备不同的优先级,符号较多不用记,现用现查就可以。
  • 当无法确定谁的优先级高时,加一个小括号就解决了。

优先级

运算符

名称或含义

使用形式

结合方向

说明

1

[]

数组下标

数组名[常量表达式]

左到右

--

()

圆括号

(表达式)/函数名(形参表)

--

.

成员选择(对象)

对象.成员名

--

->

成员选择(指针)

对象指针->成员名

--

2

-

负号运算符

-表达式

右到左

单目运算符

~

按位取反运算符

~表达式

++

自增运算符

++变量名/变量名++

--

自减运算符

--变量名/变量名--

*

取值运算符

*指针变量

&

取地址运算符

&变量名

!

逻辑非运算符

!表达式

(类型)

强制类型转换

(数据类型)表达式

--

sizeof

长度运算符

sizeof(表达式)

--

3

/

表达式/表达式

左到右

双目运算符

*

表达式*表达式

%

余数(取模)

整型表达式%整型表达式

4

+

表达式+表达式

左到右

双目运算符

-

表达式-表达式

5

<<

左移

变量<<表达式

左到右

双目运算符

>>

右移

变量>>表达式

6

>

大于

表达式>表达式

左到右

双目运算符

>=

大于等于

表达式>=表达式

<

小于

表达式<表达式

<=

小于等于

表达式<=表达式

7

==

等于

表达式==表达式

左到右

双目运算符

=

不等于

表达式!= 表达式

8

&

按位与

表达式&表达式

左到右

双目运算符

9

^

按位异或

表达式^表达式

左到右

双目运算符

10

|

按位或

表达式|表达式

左到右

双目运算符

11

&&

逻辑与

表达式&&表达式

左到右

双目运算符

12

||

逻辑或

表达式||表达式

左到右

双目运算符

13

?:

条件运算符

表达式1?

表达式2: 表达式3

右到左

三目运算符

14

=

赋值运算符

变量=表达式

右到左

--

/=

除后赋值

变量/=表达式

--

*=

乘后赋值

变量*=表达式

--

%=

取模后赋值

变量%=表达式

--

+=

加后赋值

变量+=表达式

--

-=

减后赋值

变量-=表达式

--

<<=

左移后赋值

变量<<=表达式

--

>>=

右移后赋值

变量>>=表达式

--

&=

按位与后赋值

变量&=表达式

--

^=

按位异或后赋值

变量^=表达式

--

|=

按位或后赋值

变量|=表达式

--

15

逗号运算符

表达式,表达式,…

左到右

--

上一篇:Leetcode 406. 根据身高重建队列


下一篇:rust wasm入门