二进制运算符和表达式如何构成复杂的长尾词?

2026-04-12 03:211阅读0评论SEO教程
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计4329个文字,预计阅读时间需要18分钟。

二进制运算符和表达式如何构成复杂的长尾词?

1+运算符号+什么运算符号?+运算符号是用来表示某种运算(操作)的符号。例如:+-*/%几目运算符号?+表示这个运算符需要几个操作数(运算数)+单目运算符:该运算符只需要一个操作数,例如:++++-

1 运算符

什么运算符?

​ 运算符是用来表示某种运算(操作)的符号.

如 : + - * /

几目运算符? 表示这个运算符需要几个操作数(运算数)

单目运算符 : 该运算符只需要一个操作数, 如 : ++ , -- &

双目运算符 : 该运算符需要两个操作数, 如 : + - * /

三目运算符 : 该运算符需要三个操作数, 如 : ? :

结合性 : 决定先算哪个操作数的问题.

从左到右结合, 从右到左

举个例子 :

已知 + 结合性 "从左到右" 结合,在C语言中 :

a + b 和 b + a 含义是不一样的.

运算符的优先级

在含有多个运算符的表达式中,决定先算哪个运算符,后算哪个运算符的问题.

如 : a + b*c

==单目运算符 > 算数运算符 > 关系运算符 > 逻辑运算符 > 赋值运算符 > 逗号运算符==

2 表达式

什么是表达式?

表达式是表达某种意思的式子.

C语言中的表达式 ,一般来说用运算符连接操作数的式子 , 如 : 3 + 5

表示式的值

是一个表达式,就一定会有一个值,这个值就是表达式的值.

表达式最终需要表达某个意思,某个意思就是表达式的值.

int a = 3 + 5; 这是一条语句,表达式加上一个 ; 就是一条语句.

3 运算符分类

3.1 算数运算符

进行算数运算的运算符

  • ++ -- 单目运算符

  • + - * / % 双目运算符

    / 只需要操作数是一个数(整数,也可以是小数) 就行

    % 求余数,要求两个操作数都必须为整数

    如 :

    3 + 4 => 7 3 + 4.0 => 7.0 4/2 => 2 4/2.0 => 2.0 3/2 =>1 3/2.0 => 1.5 3.5 % 2 error 3 % 2 => 1 -3 % 2 (超出知识范围) -3 % -2 (double)(3/2) => 1.0 (double)3/2 => 1.5 用c语言的表达式 来描述数学表达式 a/b 1.0*a/b

    ++ (自增运算符)

    自增(+1)运算符,单目运算符,要求操作数必须为一个左值而且是一个整数(整型变量)

    5++ //error (a + b)++ //error 表示式一定会有一个值 int x; x++; //可以的 ++x; //可以的 char y; y++; //可以的 前置++ : ++ 在前面 如 : ++x 后置++ : ++ 在后面 如 : x++

    -- (自减运算符)

    自减(-1)运算符,单目运算符,要求操作数必须为一个左值而且是一个整数(整型变量)

    前置 -- : -- 在前面 ,如 : --x 后置 -- : -- 在后面 ,如 : x-- 表达式的值 做完表达式后,i的值 i++ i i = i + 1 ++i i+1 i = i + 1 i-- i i = i - 1 --i i-1 i = i - 1

    例子 :

    int main() { int i = 5,j = 6; int a; a = (i++) + (i + j); printf("a = %d\n",a);//17 return 0; } int main() { int i = 5,j = 6; int b; b = (++i) + (i + j); printf("b = %d\n",b);//18 return 0; }

3.2 关系运算符

​ 用来判断两个东东的关系的运算符."关系" : 数值的大小关系

双目运算符, 结合性从左到右

< <= > >= == !=

关系表达式 : 用关系运算符连接起来的式子. 如 : a < b

关系表达式的值 :

关系成立 1

关系不成立 0

如 : 3 > 5 表达式的值 0 5 > 4 表示式的值 1 5 > 4 > 3 表达式的值是 0 结合性从左到右 ==> (5 > 4) > 3 ==> 1 > 3 ==> 0 5 > 4 > 3 是一个合法的表达式,先拿表达式 5 > 4 的值 和 3进行比较 在C语言中 , 5 > 4 > 3 表达式 和 数学上 5 > 4 > 3 的含义不一样 (1) C语言中, 5 > 4 > 3 <==> (5 > 4) > 3 (2) 数学中, 5 > 4 > 3 是 "5 > 4 并且 4 > 3"

3.3 逻辑运算符

! 逻辑非 单目运算符 "取反" && 逻辑与 双目运算符 "并且",从左到右 || 逻辑或 双目运算符 "或者",从左到右 逻辑表达式:用逻辑运算符(! && ||)连接起来的式子. 逻辑表达式的值: 逻辑真 1(非0) 逻辑假 0

例子 :

int a = 4,b = 5; a && b ==> 1 a || b ==> 1 !a && b ==> 0 && b ==> 0 5 > 3 && 8 < 4 - !0 5 > 3 && 8 < 4 - 1 5 > 3 && 8 < 3 1 && 0 ==> 0

练习 :

1.分析如下程序的输出结果

int main() { int a,b,c,d,m,n; a = 1; b = 2; c = 3; d = 4; m = 1; n = 1; ( m = a > b ) && (n = c > d); printf("%d,%d,%d,%d,%d,%d\n",a,b,c,d,m,n); return 0; }

C 语言运算符是 "惰性运算符"

(1) a && b && c

​ 只有a为真时,才需要判断b的值

只有a 和 b 都为真时,才需要去判断c的值

(2) a || b || c

​ 只要a 为真 ,就不必判断b 和 c 的值了

只有a 和 b 都为假的时,才需要判断c的值

总结 : 如果事先知道表达式的值,那么后面的运算符或表达式就不执行.这就是C语言运算符的"惰性''.

3.4 位运算符

​ 位运算符是按bit位展开来进行运算.意思是说,操作数展开成bit位,然后在进行运算.

位运算符要求操作数必须为整数(兼容的整数类型)

& 按位与 | 按位或 ^ 按位异或 ~ 按位取反 << 按位左移 >> 按位右移 除了~(按位取反)是单目运算符,其他的都是双目运算符,结合性从左到右

(1) ~ 按位取反

1 -> 0 0 -> 1

~3 : 00000000 00000000 00000000 00000011 11111111 11111111 11111111 11111100 <- ~3 printf("%d\n",~3);//-4

==注意:==

​ 按位取反~ 和 逻辑非 ! 的区别

!x ~x 两个都是单目运算符

~ 要求操作数是整数

! 对x无要求

(2) & 按位与

a & b , 双目运算符 , 结合性从左到右

a b a&b 1 1 1 1 0 0 0 1 0 0 0 0

& 按位与 如果两个bit位都为1,结果才为1,否则 0

例子 :

3 & 5 = ? //1 00000000 00000000 00000000 00000011 00000000 00000000 00000000 00000101 & 00000000 00000000 00000000 00000001 3 & 7 = ? //3 00000000 00000000 00000000 00000011 00000000 00000000 00000000 00000111 & 00000000 00000000 00000000 00000011

#include <stdio.h> int main() { printf("%d\n",3&7);//3 printf("%d\n",3&&7);//1 int a = 3.5 & 3.7;//error,位运算符要去 操作数是 整数类型 int b = 3.5 && 4.7;//可以的 return 0; }

==注意:==

按位与 & 和 逻辑的区别

练习 :

假设有一个整型变量a,要把a的第5 bit,变为0,其他bit位不变,该如何去操作.

a = a & ~(1<<5)

结论 :

  • 一个bit位 与 0 进行 ''按位与 & '' 操作,结果 0

    x & 0 => 0

  • 一个bit 位 与 1 进行"按位与 &"操作 ,结果为 x

    x & 1 => x

(3) 按位或 |

a | b 双目运算符 , 结合性从左到右

a b a|b 1 1 1 1 0 1 0 1 1 0 0 0

按位或 ,只要有一个bit位操作数为1,其结果就是 1

例子 :

3 | 7 = ?//7 00000000 00000000 00000000 00000011 00000000 00000000 00000000 00000111 | 00000000 00000000 00000000 00000111 3 || 7 = ? //1

练习 :

假设有一个整型变量a,要使a的第5bit置1,其他bit位不变,该如何操作?

a = a | (1 << 5)

结论 :

  • 一个bit位 与 1 "按位或 | "操作 ,结果 1

    x | 1 => 1

  • 一个bit位与0进行"按位或 | "操作 ,结果 为 x (保留原值)

    x | 0 => x

(4) 按位异或 ^

"异或" : 求异, 不同为1, 相同为 0

a ^ b ,双目运算符 ,结合性从左到右

a b a^b 1 1 0 1 0 1 0 1 1 0 0 0

例子 :

二进制运算符和表达式如何构成复杂的长尾词?

3 ^ 6 = ? //5 00000000 00000000 00000000 00000011 3 00000000 00000000 00000000 00000110 6 00000000 00000000 00000000 00000101 5

练习 :

假设有一个整型变量a ,要使a的第5bit保留,其他位取反,该如何操作?

a = a ^ ~(1 << 5)

结论 :

  • 一个bit 位与 0 进行"按位异或 ^ " 操作 ,结果为 x (保留原值)

    x ^ 0 => x

    证明 :

    ​ when x = 1,1 ^ 0 = 1

    ​ when x = 0,0^0 = 0

  • 一个bit位与1进行"按位异或 ^ "操作 ,结果 ~x(取反)

    x ^ 1 => ~x

    证明 :

    ​ when x = 1,1^1 = 0

    ​ when x = 0, 0^1= 1

(5) 按位左移 <<

a << n 双目运算符,结合性从左到右, "把 a 按bit位整体左移 n 位"

高位左移后, 舍弃, 低位空出 n 位,直接补 0;

如果左移舍弃的高位都为 0, 那么左移 n 位, 就表示 在原值乘以 2 的 n 次方.

例子 :

int a = 8 << 2; 00000000 000000000 00000000 0000 1000 <<2 00000000 000000000 00000000 0010 0000 char a = (unsigned char)-1 <<2; printf("%d\n",a);//-4 printf("%u\n",a);//2^32 -4 (unsigned char)-1 : 1111 1111 a : 1111 1100 %d : a -> int 短的 --> 长的 11111111 111111111 111111111 1111 1100 -4 %u : a -> unsigned int 短的 --> 长的 11111111 111111111 111111111 1111 1100 2^32 -4

练习 :

​ 构造一个整数,他的 第7bit位 和 第 28bit位为 1,其他的bit位 为 0 ,该如何构造?

(1<<7)|(1<<28) (1<<7) + (1<<28)

(6) 按位右移 >>

x >> n 双目运算符, 从左到右结合, "把x按bit为, 整体右移n位"

低位右移后,直接舍弃,高位补什么呢?

对于无符号数(x) , 高位全部补0,

对于有符号数(x),高位全部补符号位.

练习 :

1.分析如下程序的输出结果,假设 int 32bits

int main() { int a = -1; 11111111 111111111 111111111 11111111 a = a >> 31; 11111111 111111111 111111111 11111111 printf("%d\n",a);//-1 printf("%u\n",a);//2^32 -1 return 0; }

int main() { unsigned int a = -1; 11111111 111111111 111111111 11111111 a = a >> 31; 00000000 00000000 00000000 00000001 printf("%d\n",a);//1 printf("%u\n",a);//1 return 0; }

2.分析如下程序的输出结果, 假设int 32bits

int main() { char a = -1; int b = a >> 31; -1 : 11111111 11111111 11111111 11111111 a : 11111111 a -> int : 11111111 11111111 11111111 11111111 b : 11111111 11111111 11111111 11111111 printf("%d\n",b);//-1 printf("%u\n",b);//2^32 -1 return 0; }

int main() { unsigned char a = -1; int b = a >> 31; -1 : 11111111 11111111 11111111 11111111 a : 11111111 a -> int : 00000000 00000000 00000000 11111111 b : 00000000 00000000 00000000 00000000 printf("%d\n",b);//0 printf("%u\n",b);//0 return 0; }

(7) 掩码(mask)

掩码(mask) 是一个位模式,表示从一个字(word,32bits)中选出的位集合.

掩码中为 1 的那些bit位, 就是我们想要选取的bit位的集合.

如 :

如果我要选取的第0个bit 和 第1个bit, 则掩码为 : 0x3 00000000 00000000 000000000 00000011 如果 mask = 0xff,表示我选取低8bits 00000000 00000000 00000000 11111111

例子 :

​ 假设有一个整型变量 x = 0x345678AB,我想选取x的低8位,该如何操作?

​ 低8位的掩码 mask = 0xff

​ x & mask ==> x & 0xff ==> 0xAB

3.5 赋值运算符

a = b,双目运算符,结合性==从右至左==,"把表达式b的值 赋值给 a"

赋值运算符的优先级 排倒数第二, 倒数第一是逗号运算符.

a = b; 把表达式 b 的值,赋值给a(把这个值写入到 a 的地址中去, a需要具备一个可写的地址,"左值") 一般来说, a 为一个可变的数据对象 "变量" 赋值运算符的 左边的操作数 必须为一个 "可写的地址" 左值 ,变量

如 :

5 = 5;//error 2 + 3 = 5;//error int x = 1.y = 3; x + y = 5;//error x = 5;//可以的 x++ = 6;//error

赋值表达式 : 由赋值运算符连接操作数的式子, 称之为赋值表达式

赋值表达式的值,就是赋完值后左边的那个操作数的值.

如 :

x = 5 这是一个赋值表达式,这个表达式的值就是最后x的值, 5 y = x = 5; 这是一个合法的赋值表达式!! ==> y = (x = 5) 把 表达式 "x = 5" 的值,赋值给y

复合赋值运算符 : 赋值运算符可以和算术运算符,位运算符组合成 复合运算符.

+= -= *= /= %= <<= >>= |= &= ^= a += b ==> a = a + b sum <<=5 ==> sum = sum <<5 sum -=i ==> sum = sum - i

3.6 条件运算符

? : 三目运算符 expressions ? a : b 先判断 expressions 的值, 如果他的值为真(非0),则整个表达式的值为 a 如果他的值为假(0) , 则整个表示式的值为b. 结合性 是从右向左.

如 :

if(a > b) { x = 250; } else { x = 360; } x = ( a > b ? 250 : 360 ); or a > b ? (x = 250) : (x = 360)

3.7 逗号运算符

a , b 双目运算符,结合性从左到右结合, 优先级是最低的.

先算表达式 a 的值, 然后在算表达式 b 的值, 整个逗号表达式的值就是最右边表达式b的值.

表达式 1 , 表达式2

例子 :

a = 3 , 2

这是一个逗号表达式,他的指值为 2

(a = 3) , 2

a = (3 , 2)

这是一个赋值表达式,把 "表达式(3 , 2)"的值,赋值给a

a = 3, a = 2

这个也是一个逗号表达式

a = 3 , a = 2 ,a = 4

这个也是逗号表达式 ==> (a = 3 , a = 2) , a = 4

...

逗号表达式的形式可以是这样的 : 扩展的逗号表达式 表达式1 , 表达式2 , 表达式3, ...,表达式n

求值的顺序: 先求表达式1的值,然后求表达式2的值,...,最后求表达式n的值,

整个逗号表达式的值,就是最右边的那个表达式的值.

3.8 指针运算符

* 指向运算符 & 取地址符 后面在讲

3.9 求字节运算符

sizeof

3.10 分量运算符

. ->

3.11 下标运算符

[] 取数组元素 int a[10]; a[0] a[1] ...

3.12 强制类型转换运算符

(类型)表达式 如 : (int)3.5 (int)(3.1 + 4.7)

3.13 其他

函数调用运算.

4 运算符的优先级和结合性

运算符 结合性 () [] -> . 从左向右 ! ~ ++ -- +(正号) -(负号) *(指针) &(取地址) (type) sizeof 从右向左 * / % 从左到右 + 加 - 减 从左到右 << >> 从左到右 < <= > >= 从左到右 == != 从左到右 & 按位与 从左到右 ^ 按位异或 从左到右 | 按位或 从左到右 && 从左到右 || 从左到右 ? : 从右向左 = += -= *= /= %= &= 从右向左 ^= |= <<= >>= 从右向左 , 从左向右

通用办法 : ==如果不确定优先级,那就用 ( ) 来解决==

本文共计4329个文字,预计阅读时间需要18分钟。

二进制运算符和表达式如何构成复杂的长尾词?

1+运算符号+什么运算符号?+运算符号是用来表示某种运算(操作)的符号。例如:+-*/%几目运算符号?+表示这个运算符需要几个操作数(运算数)+单目运算符:该运算符只需要一个操作数,例如:++++-

1 运算符

什么运算符?

​ 运算符是用来表示某种运算(操作)的符号.

如 : + - * /

几目运算符? 表示这个运算符需要几个操作数(运算数)

单目运算符 : 该运算符只需要一个操作数, 如 : ++ , -- &

双目运算符 : 该运算符需要两个操作数, 如 : + - * /

三目运算符 : 该运算符需要三个操作数, 如 : ? :

结合性 : 决定先算哪个操作数的问题.

从左到右结合, 从右到左

举个例子 :

已知 + 结合性 "从左到右" 结合,在C语言中 :

a + b 和 b + a 含义是不一样的.

运算符的优先级

在含有多个运算符的表达式中,决定先算哪个运算符,后算哪个运算符的问题.

如 : a + b*c

==单目运算符 > 算数运算符 > 关系运算符 > 逻辑运算符 > 赋值运算符 > 逗号运算符==

2 表达式

什么是表达式?

表达式是表达某种意思的式子.

C语言中的表达式 ,一般来说用运算符连接操作数的式子 , 如 : 3 + 5

表示式的值

是一个表达式,就一定会有一个值,这个值就是表达式的值.

表达式最终需要表达某个意思,某个意思就是表达式的值.

int a = 3 + 5; 这是一条语句,表达式加上一个 ; 就是一条语句.

3 运算符分类

3.1 算数运算符

进行算数运算的运算符

  • ++ -- 单目运算符

  • + - * / % 双目运算符

    / 只需要操作数是一个数(整数,也可以是小数) 就行

    % 求余数,要求两个操作数都必须为整数

    如 :

    3 + 4 => 7 3 + 4.0 => 7.0 4/2 => 2 4/2.0 => 2.0 3/2 =>1 3/2.0 => 1.5 3.5 % 2 error 3 % 2 => 1 -3 % 2 (超出知识范围) -3 % -2 (double)(3/2) => 1.0 (double)3/2 => 1.5 用c语言的表达式 来描述数学表达式 a/b 1.0*a/b

    ++ (自增运算符)

    自增(+1)运算符,单目运算符,要求操作数必须为一个左值而且是一个整数(整型变量)

    5++ //error (a + b)++ //error 表示式一定会有一个值 int x; x++; //可以的 ++x; //可以的 char y; y++; //可以的 前置++ : ++ 在前面 如 : ++x 后置++ : ++ 在后面 如 : x++

    -- (自减运算符)

    自减(-1)运算符,单目运算符,要求操作数必须为一个左值而且是一个整数(整型变量)

    前置 -- : -- 在前面 ,如 : --x 后置 -- : -- 在后面 ,如 : x-- 表达式的值 做完表达式后,i的值 i++ i i = i + 1 ++i i+1 i = i + 1 i-- i i = i - 1 --i i-1 i = i - 1

    例子 :

    int main() { int i = 5,j = 6; int a; a = (i++) + (i + j); printf("a = %d\n",a);//17 return 0; } int main() { int i = 5,j = 6; int b; b = (++i) + (i + j); printf("b = %d\n",b);//18 return 0; }

3.2 关系运算符

​ 用来判断两个东东的关系的运算符."关系" : 数值的大小关系

双目运算符, 结合性从左到右

< <= > >= == !=

关系表达式 : 用关系运算符连接起来的式子. 如 : a < b

关系表达式的值 :

关系成立 1

关系不成立 0

如 : 3 > 5 表达式的值 0 5 > 4 表示式的值 1 5 > 4 > 3 表达式的值是 0 结合性从左到右 ==> (5 > 4) > 3 ==> 1 > 3 ==> 0 5 > 4 > 3 是一个合法的表达式,先拿表达式 5 > 4 的值 和 3进行比较 在C语言中 , 5 > 4 > 3 表达式 和 数学上 5 > 4 > 3 的含义不一样 (1) C语言中, 5 > 4 > 3 <==> (5 > 4) > 3 (2) 数学中, 5 > 4 > 3 是 "5 > 4 并且 4 > 3"

3.3 逻辑运算符

! 逻辑非 单目运算符 "取反" && 逻辑与 双目运算符 "并且",从左到右 || 逻辑或 双目运算符 "或者",从左到右 逻辑表达式:用逻辑运算符(! && ||)连接起来的式子. 逻辑表达式的值: 逻辑真 1(非0) 逻辑假 0

例子 :

int a = 4,b = 5; a && b ==> 1 a || b ==> 1 !a && b ==> 0 && b ==> 0 5 > 3 && 8 < 4 - !0 5 > 3 && 8 < 4 - 1 5 > 3 && 8 < 3 1 && 0 ==> 0

练习 :

1.分析如下程序的输出结果

int main() { int a,b,c,d,m,n; a = 1; b = 2; c = 3; d = 4; m = 1; n = 1; ( m = a > b ) && (n = c > d); printf("%d,%d,%d,%d,%d,%d\n",a,b,c,d,m,n); return 0; }

C 语言运算符是 "惰性运算符"

(1) a && b && c

​ 只有a为真时,才需要判断b的值

只有a 和 b 都为真时,才需要去判断c的值

(2) a || b || c

​ 只要a 为真 ,就不必判断b 和 c 的值了

只有a 和 b 都为假的时,才需要判断c的值

总结 : 如果事先知道表达式的值,那么后面的运算符或表达式就不执行.这就是C语言运算符的"惰性''.

3.4 位运算符

​ 位运算符是按bit位展开来进行运算.意思是说,操作数展开成bit位,然后在进行运算.

位运算符要求操作数必须为整数(兼容的整数类型)

& 按位与 | 按位或 ^ 按位异或 ~ 按位取反 << 按位左移 >> 按位右移 除了~(按位取反)是单目运算符,其他的都是双目运算符,结合性从左到右

(1) ~ 按位取反

1 -> 0 0 -> 1

~3 : 00000000 00000000 00000000 00000011 11111111 11111111 11111111 11111100 <- ~3 printf("%d\n",~3);//-4

==注意:==

​ 按位取反~ 和 逻辑非 ! 的区别

!x ~x 两个都是单目运算符

~ 要求操作数是整数

! 对x无要求

(2) & 按位与

a & b , 双目运算符 , 结合性从左到右

a b a&b 1 1 1 1 0 0 0 1 0 0 0 0

& 按位与 如果两个bit位都为1,结果才为1,否则 0

例子 :

3 & 5 = ? //1 00000000 00000000 00000000 00000011 00000000 00000000 00000000 00000101 & 00000000 00000000 00000000 00000001 3 & 7 = ? //3 00000000 00000000 00000000 00000011 00000000 00000000 00000000 00000111 & 00000000 00000000 00000000 00000011

#include <stdio.h> int main() { printf("%d\n",3&7);//3 printf("%d\n",3&&7);//1 int a = 3.5 & 3.7;//error,位运算符要去 操作数是 整数类型 int b = 3.5 && 4.7;//可以的 return 0; }

==注意:==

按位与 & 和 逻辑的区别

练习 :

假设有一个整型变量a,要把a的第5 bit,变为0,其他bit位不变,该如何去操作.

a = a & ~(1<<5)

结论 :

  • 一个bit位 与 0 进行 ''按位与 & '' 操作,结果 0

    x & 0 => 0

  • 一个bit 位 与 1 进行"按位与 &"操作 ,结果为 x

    x & 1 => x

(3) 按位或 |

a | b 双目运算符 , 结合性从左到右

a b a|b 1 1 1 1 0 1 0 1 1 0 0 0

按位或 ,只要有一个bit位操作数为1,其结果就是 1

例子 :

3 | 7 = ?//7 00000000 00000000 00000000 00000011 00000000 00000000 00000000 00000111 | 00000000 00000000 00000000 00000111 3 || 7 = ? //1

练习 :

假设有一个整型变量a,要使a的第5bit置1,其他bit位不变,该如何操作?

a = a | (1 << 5)

结论 :

  • 一个bit位 与 1 "按位或 | "操作 ,结果 1

    x | 1 => 1

  • 一个bit位与0进行"按位或 | "操作 ,结果 为 x (保留原值)

    x | 0 => x

(4) 按位异或 ^

"异或" : 求异, 不同为1, 相同为 0

a ^ b ,双目运算符 ,结合性从左到右

a b a^b 1 1 0 1 0 1 0 1 1 0 0 0

例子 :

二进制运算符和表达式如何构成复杂的长尾词?

3 ^ 6 = ? //5 00000000 00000000 00000000 00000011 3 00000000 00000000 00000000 00000110 6 00000000 00000000 00000000 00000101 5

练习 :

假设有一个整型变量a ,要使a的第5bit保留,其他位取反,该如何操作?

a = a ^ ~(1 << 5)

结论 :

  • 一个bit 位与 0 进行"按位异或 ^ " 操作 ,结果为 x (保留原值)

    x ^ 0 => x

    证明 :

    ​ when x = 1,1 ^ 0 = 1

    ​ when x = 0,0^0 = 0

  • 一个bit位与1进行"按位异或 ^ "操作 ,结果 ~x(取反)

    x ^ 1 => ~x

    证明 :

    ​ when x = 1,1^1 = 0

    ​ when x = 0, 0^1= 1

(5) 按位左移 <<

a << n 双目运算符,结合性从左到右, "把 a 按bit位整体左移 n 位"

高位左移后, 舍弃, 低位空出 n 位,直接补 0;

如果左移舍弃的高位都为 0, 那么左移 n 位, 就表示 在原值乘以 2 的 n 次方.

例子 :

int a = 8 << 2; 00000000 000000000 00000000 0000 1000 <<2 00000000 000000000 00000000 0010 0000 char a = (unsigned char)-1 <<2; printf("%d\n",a);//-4 printf("%u\n",a);//2^32 -4 (unsigned char)-1 : 1111 1111 a : 1111 1100 %d : a -> int 短的 --> 长的 11111111 111111111 111111111 1111 1100 -4 %u : a -> unsigned int 短的 --> 长的 11111111 111111111 111111111 1111 1100 2^32 -4

练习 :

​ 构造一个整数,他的 第7bit位 和 第 28bit位为 1,其他的bit位 为 0 ,该如何构造?

(1<<7)|(1<<28) (1<<7) + (1<<28)

(6) 按位右移 >>

x >> n 双目运算符, 从左到右结合, "把x按bit为, 整体右移n位"

低位右移后,直接舍弃,高位补什么呢?

对于无符号数(x) , 高位全部补0,

对于有符号数(x),高位全部补符号位.

练习 :

1.分析如下程序的输出结果,假设 int 32bits

int main() { int a = -1; 11111111 111111111 111111111 11111111 a = a >> 31; 11111111 111111111 111111111 11111111 printf("%d\n",a);//-1 printf("%u\n",a);//2^32 -1 return 0; }

int main() { unsigned int a = -1; 11111111 111111111 111111111 11111111 a = a >> 31; 00000000 00000000 00000000 00000001 printf("%d\n",a);//1 printf("%u\n",a);//1 return 0; }

2.分析如下程序的输出结果, 假设int 32bits

int main() { char a = -1; int b = a >> 31; -1 : 11111111 11111111 11111111 11111111 a : 11111111 a -> int : 11111111 11111111 11111111 11111111 b : 11111111 11111111 11111111 11111111 printf("%d\n",b);//-1 printf("%u\n",b);//2^32 -1 return 0; }

int main() { unsigned char a = -1; int b = a >> 31; -1 : 11111111 11111111 11111111 11111111 a : 11111111 a -> int : 00000000 00000000 00000000 11111111 b : 00000000 00000000 00000000 00000000 printf("%d\n",b);//0 printf("%u\n",b);//0 return 0; }

(7) 掩码(mask)

掩码(mask) 是一个位模式,表示从一个字(word,32bits)中选出的位集合.

掩码中为 1 的那些bit位, 就是我们想要选取的bit位的集合.

如 :

如果我要选取的第0个bit 和 第1个bit, 则掩码为 : 0x3 00000000 00000000 000000000 00000011 如果 mask = 0xff,表示我选取低8bits 00000000 00000000 00000000 11111111

例子 :

​ 假设有一个整型变量 x = 0x345678AB,我想选取x的低8位,该如何操作?

​ 低8位的掩码 mask = 0xff

​ x & mask ==> x & 0xff ==> 0xAB

3.5 赋值运算符

a = b,双目运算符,结合性==从右至左==,"把表达式b的值 赋值给 a"

赋值运算符的优先级 排倒数第二, 倒数第一是逗号运算符.

a = b; 把表达式 b 的值,赋值给a(把这个值写入到 a 的地址中去, a需要具备一个可写的地址,"左值") 一般来说, a 为一个可变的数据对象 "变量" 赋值运算符的 左边的操作数 必须为一个 "可写的地址" 左值 ,变量

如 :

5 = 5;//error 2 + 3 = 5;//error int x = 1.y = 3; x + y = 5;//error x = 5;//可以的 x++ = 6;//error

赋值表达式 : 由赋值运算符连接操作数的式子, 称之为赋值表达式

赋值表达式的值,就是赋完值后左边的那个操作数的值.

如 :

x = 5 这是一个赋值表达式,这个表达式的值就是最后x的值, 5 y = x = 5; 这是一个合法的赋值表达式!! ==> y = (x = 5) 把 表达式 "x = 5" 的值,赋值给y

复合赋值运算符 : 赋值运算符可以和算术运算符,位运算符组合成 复合运算符.

+= -= *= /= %= <<= >>= |= &= ^= a += b ==> a = a + b sum <<=5 ==> sum = sum <<5 sum -=i ==> sum = sum - i

3.6 条件运算符

? : 三目运算符 expressions ? a : b 先判断 expressions 的值, 如果他的值为真(非0),则整个表达式的值为 a 如果他的值为假(0) , 则整个表示式的值为b. 结合性 是从右向左.

如 :

if(a > b) { x = 250; } else { x = 360; } x = ( a > b ? 250 : 360 ); or a > b ? (x = 250) : (x = 360)

3.7 逗号运算符

a , b 双目运算符,结合性从左到右结合, 优先级是最低的.

先算表达式 a 的值, 然后在算表达式 b 的值, 整个逗号表达式的值就是最右边表达式b的值.

表达式 1 , 表达式2

例子 :

a = 3 , 2

这是一个逗号表达式,他的指值为 2

(a = 3) , 2

a = (3 , 2)

这是一个赋值表达式,把 "表达式(3 , 2)"的值,赋值给a

a = 3, a = 2

这个也是一个逗号表达式

a = 3 , a = 2 ,a = 4

这个也是逗号表达式 ==> (a = 3 , a = 2) , a = 4

...

逗号表达式的形式可以是这样的 : 扩展的逗号表达式 表达式1 , 表达式2 , 表达式3, ...,表达式n

求值的顺序: 先求表达式1的值,然后求表达式2的值,...,最后求表达式n的值,

整个逗号表达式的值,就是最右边的那个表达式的值.

3.8 指针运算符

* 指向运算符 & 取地址符 后面在讲

3.9 求字节运算符

sizeof

3.10 分量运算符

. ->

3.11 下标运算符

[] 取数组元素 int a[10]; a[0] a[1] ...

3.12 强制类型转换运算符

(类型)表达式 如 : (int)3.5 (int)(3.1 + 4.7)

3.13 其他

函数调用运算.

4 运算符的优先级和结合性

运算符 结合性 () [] -> . 从左向右 ! ~ ++ -- +(正号) -(负号) *(指针) &(取地址) (type) sizeof 从右向左 * / % 从左到右 + 加 - 减 从左到右 << >> 从左到右 < <= > >= 从左到右 == != 从左到右 & 按位与 从左到右 ^ 按位异或 从左到右 | 按位或 从左到右 && 从左到右 || 从左到右 ? : 从右向左 = += -= *= /= %= &= 从右向左 ^= |= <<= >>= 从右向左 , 从左向右

通用办法 : ==如果不确定优先级,那就用 ( ) 来解决==