一.进制转换与2进制表示1.概念其实我们经常能听到 2 进制、 8 进制、 10 进制、 16 进制 这样的讲法那是什么意思呢 其实2进制、8进制、10进制、16进制是数值的不同表⽰形式⽽已。⽐如数值15的各种进制的表⽰形式15 的 2 进制 111115 的 8 进制1715 的 10 进制 1515 的 16 进制 F我们重点介绍⼀下⼆进制 ⾸先我们还是得从10进制讲起其实10进制是我们⽣活中经常使⽤的我们已经形成了很多尝试• 10进制中满10进1• 10进制的数字每⼀位都是0~9的数字组成其实⼆进制也是⼀样的• 2进制中满2进1• 2进制的数字每⼀位都是0~1的数字组成 那么 1101 就是⼆进制的数字了。那么8进制的数字每⼀位都是0~7的数字组成16进制的数字每⼀位都是0~15的数字组成但是为了以防混淆通常用ABCDEF来表示101112131415。2.进制转换2.1其实10进制的123表⽰的值是⼀百⼆⼗三为什么是这个值呢其实10进制的每⼀位是有权重的10 进制的数字从右向左是个位、⼗位、百位....分别每⼀位的权重是 10^0 ,10^1 ,10^2 ...如图2进制和10进制是类似的只不过2进制的每⼀位的权重从右向左是: 2 ,2 ,2 ... 0 1 2 如果是2进制的1101该怎么理解呢如图2.2.10进制转2进制数字如图2.3.2进制转8进制8进制的数字每⼀位是0~7的0~7的数字各⾃写成2进制最多有3个2进制位就⾜够了⽐如7的⼆ 进制是111所以在2进制转8进制数的时候从2进制序列中右边低位开始向左每3个2进制位会换算⼀ 个8进制位剩余不够3个2进制位的直接换算。如图如2进制的01101011换成8进制01530开头的数字会被当做8进制2.4.2进制转16进制16进制的数字每⼀位是0~9,a~f的0~9,a~f的数字各⾃写成2进制最多有4个2进制位就⾜够了 ⽐如f的⼆进制是1111所以在2进制转16进制数的时候从2进制序列中右边低位开始向左每4个2进 制位会换算⼀个16进制位剩余不够4个⼆进制位的直接换算。如2进制的01101011换成16进制0x6b16进制表⽰的时候前⾯加0x如图3.原码、反码、补码整数的2进制表⽰⽅法有三种即原码、反码和补码。有符号整数的三种表⽰⽅法均有符号位和数值位两部分2进制序列中最⾼位的1位是被当做符号 位剩余的都是数值位。符号位都是⽤0表⽰“正”⽤1表⽰“负”。注意正整数的原、反、补码都相同但是负整数的三种表示方法法各不相同。概念原码直接将数值按照正负数的形式翻译成⼆进制得到的就是原码。反码将原码的符号位不变其他位依次按位取反就可以得到反码补码反码1就得到补码。注意补码得到原码也是可以使用取反1的操作。对于整形来说数据存放内存中其实存放的是补码。原因在计算机系统中数值⼀律⽤补码来表⽰和存储。原因在于使⽤补码可以将符号位和数值域统⼀ 处理同时加法和减法也可以统⼀处理CPU只有加法器此外补码与原码相互转换其运算 过程是相同的不需要额外的硬件电路。二.移位操作符1.左移操作符()移位规则左边抛弃、右边补0例如#include stdio.h int main() { int num 10; int n num1; printf(n %d\n, n); printf(num %d\n, num); return 0; }如图2.右移操作符移位规则⾸先右移运算分两种1. 逻辑右移左边⽤0填充右边丢弃。2. 算术右移左边⽤原该值的符号位填充右边丢弃。例如#include stdio.h int main() { int num -1; int n num1; printf(n %d\n, n); printf(num %d\n, num); return 0; }如图警告对于移位运算符不要移动负数位这个是标准未定义的。三.位操作符注 位操作数必须是整数。1.规则1.1.按位与规则只有当两个对应的位置都为 1 时结果才为 1如果其中一个是 0或者两个都是 0结果就是 0同1为1否则为0实例演练12 2512的二进制0 1 1 0 025的二进制1 1 0 0 10 1 1 0 0 (12) 1 1 0 0 1 (25)-----------0 1 0 0 0 (结果)1.2.|按位或规则只要对应的位置里有一个 1结果就是 1。只有当两个都是 0 时它才会给出 0有1为1同0为0。实例演练12 | 2512的二进制0 1 1 0 025的二进制1 1 0 0 10 1 1 0 0 (12)| 1 1 0 0 1 (25)-----------1 1 1 0 1 (结果)1.3.^按位异或规则只有当两个位不同时结果才为 1如果两个位相等全是 0 或全是 1结果就是 0相同为0不同为1。12的二进制0 1 1 0 025的二进制1 1 0 0 10 1 1 0 0 (12)^ 1 1 0 0 1 (25)-----------1 0 1 0 1 (结果)1.4.~按位取反规则0 变成 1,1 变成 0。例如#includestdio.h int main() { int a 5; printf(%d, ~a); // 输出结果是 -6 return 0; }过程5的二进制假设 8 位0000 0101。取反后1111 1010计算机解读最左边是 1表示这是一个负数。在计算机补码系统中1111 1010代表的就是-6。2.练习2.1.不 能创建临时变量第三个变量实现两个整数的交换。注意到a^a0a^0a;规律任何数字和自己异或结果绝对是 0。任何数字和 0 异或结果还是它自己。代码#include stdio.h int main() { int a 10; int b 20; a a^b; b a^b; aa^b; printf(a %d b %d\n, a, b); return 0; }2.2.求⼀个整数存储在内存中的⼆进制中1的个数。法1.#include stdio.h int main() { int num -1; int i 0; int count 0; // 用于统计 1 的个数 // int 通常占 4 个字节即 32 个位bit for(i 0; i 32; i) { /* (1 i) 的作用 当 i0 时生成 000...0001 当 i1 时生成 000...0010 ...以此类推将 1 移动到第 i 位 */ /* num (1 i) 的作用按位与 只有当 num 的第 i 位也是 1 时结果才为“真”非0 */ if( num (1 i) ) { count; // 如果该位是 1计数器加 1 } } printf(二进制中 1 的个数 %d\n, count); // 结果会输出 32 return 0; }法2.#include stdio.h int main() { int num -1; // 在补码中-1 是 32 个 1 int count 0; // 计数器 // 只要 num 不为 0就继续循环 while(num) { count; // 只要进来了说明 num 至少还有一个 1 num num (num - 1); // 魔法步骤消掉最右边的 1 } printf(二进制中 1 的个数 %d\n, count); return 0; }四.其他操作符1.逗号表达式语法表示exp1, exp2, exp3, …expN规则逗号表达式就是⽤逗号隔开的多个表达式。逗号表达式从左向右依次执⾏。整个表达式的结果是最后⼀个表达式的结果。例如#include stdio.h int main() { int a 1, b 2, c 0; // 1. 核心用法c 拿的是最后一个值 (a10) // 计算过程a先变3b先变4最后算 310 c (a 2, b 2, a 10); printf(a%d, b%d, c%d\n, a, b, c); // 输出a3, b4, c13 // 2. 常见陷阱没括号时赋值优先 int d 0; d a 5, a 10; printf(d%d\n, d); // 输出d5 (因为等号先算后面的 a10 被无视了) return 0; }2.[ ]与函数调⽤操作符2.1.[ ] 下标引⽤操作符操作数⼀个数组名⼀个索引值(下标例如int arr[10];//创建数组 arr[9] 10;//使⽤下标引⽤操作符。 //[ ]的两个操作数是arr和9。2.2.函数调⽤操作符接受⼀个或者多个操作数第⼀个操作数是函数名剩余的操作数就是传递给函数的参数。例如#include stdio.h void test1() { printf(hehe\n); } void test2(const char *str) { printf(%s\n, str); } int main() { test1();//这⾥的()就是作为函数调⽤操作符。 test2(hello bit.);//这⾥的()就是函数调⽤操作符。 return 0; }五.操作符的属性1.优先级优先级指的是如果⼀个表达式包含多个运算符哪个运算符应该优先执⾏。各种运算符的优先级是 不⼀样的。例如3 4 * 5;上⾯⽰例中表达式 3 4 * 5 ⾥⾯既有加法运算符 ⼜有乘法运算符 * 。由于乘法 的优先级⾼于加法所以会先计算 4 * 5 ⽽不是先计算 3 4。2 结合性如果两个运算符优先级相同优先级没办法确定先计算哪个了这时候就看结合性了则根据运算符 是左结合还是右结合决定执⾏顺序。⼤部分运算符是左结合从左到右执⾏少数运算符是右 结合从右到左执⾏⽐如赋值运算符 。例如5 * 6 / 2;上⾯⽰例中* 和 / 的优先级相同它们都是左结合运算符所以从左到右执⾏先计算 5 * 6 再计算 / 2 。运算符的优先级顺序很多下⾯是部分运算符的优先级顺序按照优先级从⾼到低排列建议⼤概 记住这些操作符的优先级就⾏其他操作符在使⽤的时候查看下⾯表格就可以了圆括号 () • ⾃增运算符 ⾃减运算符- • 单⽬运算符 和 • 乘法 * 除法 / • 加法 减法 • 关系运算符 、 等• 赋值运算符 参考https://zh.cppreference.com/w/c/language/operator_precedence