前言本人的技术笔记会优先发布在个人站点longyxblg.cn操作符分类原码、反码、补码整数的2进制表示方法有三种即原码、反码、补码。有符号的三种表示方法均有符号位和数值位两部分组成。首位被当作符号位剩下的均为数值位。符号位用 0 表示正用 1 表示负。正整数的原码、反码、补码都相同。负整数的三种表示方法各不相同。原码直接将数值按照正负数的形式翻译成二进制得到的就是原码。反码原码的数值位取反符号位不变。 0 变 1 1 变 0补码反码 1。例如对于整型来说其实存放在内存中的就是他的补码。inta-10;// 原码就是 a 的二进制表示// 一个整型数在内存中占 4 个字节32 位一个字节由8个 bit 位组成所以 a 的二进制表示为// 10000000 00000000 00000000 00001010 就是原码// 11111111 11111111 11111111 11110101 就是 a 的反码// 11111111 11111111 11111111 11110110 就是 a 的补码在计算机系统中数值一律用补码来表示和存储。原因在于使用补码可以将符号位和数值域统一处理同时加法和减法也可以统一处理CPU只有加法器此外补码与原码相互转换其运算过程是相同的不需要额外的硬件电路移位操作符全程操作的都是数据的补码。左移位操作符移位规则左边抛弃右边补0inta10;// 00000000 00000000 00000000 00001010intnuma1;// 左移一位相当于乘以 2// 00000000 00000000 00000000 00010100printf(%d\n,num);inta-10;// 10000000 00000000 00000000 00001010 就是 a 的原码// 11111111 11111111 11111111 11110101 就是 a 的反码// 11111111 11111111 11111111 11110110 就是 a 的补码intnuma1;// 11111111 11111111 11111111 11101100 就是 a 左移一位后的结果,这是补码// 11111111 11111111 11111111 11101011 就是 a 左移一位后的反码// 10000000 00000000 00000000 00010100 就是 a 左移一位后的原码右移位操作符右移位操作符分两种情况逻辑右移和算术右移逻辑移位规则右边抛弃左边补0inta10;// 00000000 00000000 00000000 00001010intnuma1;// 右移一位相当于除以 2// 00000000 00000000 00000000 00000101printf(%d\n,num);算术移位规则右边抛弃左边用概该数的符号位填充inta-10;// 10000000 00000000 00000000 00001010 就是 a 的原码// 11111111 11111111 11111111 11110101 就是 a 的反码// 11111111 11111111 11111111 11110110 就是 a 的补码intnuma1;// 11111111 11111111 11111111 11111011 就是 a 右移一位后的结果// 11111111 11111111 11111111 11111010 就是 a 右移一位后的反码// 10000000 00000000 00000000 00000101 就是 a 右移一位后的补码printf(%d\n,num);对于移位操作符不能移动负数位这个标准是未定义的。位操作符// 按位与|// 按位或^// 按位异或!// 按位取反注他们操作的必须是整数。 是双目操作符对两个数的补码进行操作都为1是1有0就是0| 是双目操作符对两个数的补码进行操作有1就是1都是0位0^ 是双目操作符对两个数的补码进行操作位相同为0不同为1int num1 10; // 00000000 00000000 00000000 00001010 就是 num1 的二进制表示 int num2 20; // 00000000 00000000 00000000 00010100 就是 num2 的二进制表示 printf(%d\n, num1 num2); // 都是1才是1否则为0 // 00000000 00000000 00000000 00001010 // 00000000 00000000 00000000 00010100 // 00000000 00000000 00000000 00000000 printf(%d\n, num1 | num2); // 有1为1否则为0 // 00000000 00000000 00000000 00001010 // 00000000 00000000 00000000 00010100 // 00000000 00000000 00000000 00010110 printf(%d\n, num1 ^ num2); // 相同为0不同为1 // 00000000 00000000 00000000 00001010 // 00000000 00000000 00000000 00010100 // 00000000 00000000 00000000 00010110 printf(%d\n, ~ num1); // 按位取反 // 1取00取1 // 00000000 00000000 00000000 00001010 // 11111111 11111111 11111111 11110101 就是 num1 的按位取反结果这是补码 // 11111111 11111111 11111111 11110100 这是反码 // 10000000 00000000 00000000 00001011 这是原码使用位操作符实现交换两变量的值假设现在有一变量 x ,那么 x 一定满足 x ^ x 0, 0 ^ x x , 对于变量 a,b 满足 (a ^ b) ^ c a ^ (b ^ c),即可推导出inta0;intb0;scanf(%d %d,a,b);aa^b;ba^b;aa^b;printf(a %d b %d,a,b);求一个整数存储在内存中的二进制中的 1 的个数对于 1 来说他与任意一个整数进行 运算只会出现 0 和 1 两种结果。00000000000000000000000000000001// 1在内存中的存储那么就可以这么设计// 计算一个整数的二进制表示中有多少个 1intnum0;intcount0;scanf(%d,num);for(inti0;i32;i){// 1与任意一个整数进行按位与运算如果该整数的二进制表示中对应位是 1那么结果就是 1否则就是 0if(1numi){count;// 说明 num 的二进制表示中第 i 位是 1那么就把 count 加 1}}printf(有 %d 个 1\n,count);还有一种效率更高的算法不需要循环32次intnum-1;intcount0;while(num){count;numnum(num-1);// 这个操作会把 num 的二进制表示中最后一个 1 变成 0}printf(有 %d 个 1\n,count);这个算法利用的就是每次 num num - 1 会将这个数放在末尾的1消掉。直到这个数变成0为止统计这个过程执行了多少次就知道 num 的二进制表示中有多少个 1 了。注只有在补码存储下该公式成立逗号表达式指用逗号隔开的多个表达式。从左向右依次执行整个表达式的结果是最后一个表达式的结果。inta3;intb4;intc(ab,a*b,a-b);printf(%d\n,c);这儿有一串代码atest1();test2();while(a0){// 业务处理test2();}那么根据逗号表达式的计算还可以这么写while(atest1(),test2(),a0){// 业务处理test2();}标访问[]和函数调用()这俩没啥好说的intarr[10];//创建数组 arr[9]10;//使用下标引用操作符。[]的两个操作数是arr和9voidtest1(){printf(hehe\n);}voidtest2(constchar*str){printf(%s\n,str);}intmain(){test1();//这里的()就是作为函数调用操作符。test2(hello world.);//这里的()就是函数调用操作符。return0;}结构体访问操作符这一块儿放到结构体。表达式求值整型提升C语言中整型算术运算总是至少以缺省整型类型的精度来进行的。为了获得这个精度表达式中的字符和短整型操作数在使用之前被转换为普通整型这种转换称为整型提升。chara3;charb127;charcab;printf(%d ,c);这里 a 和 b 在进行相加之前就会先提升为普通整型再执行加法计算。计算完成后结果在被截断后存放进 c 中。整型提升的规则是有符号整数提升是按照变量的数据类型的符号位来提升的无符号整数提升高位补0charcab;// a: 00000000 00000000 00000000 00000011// b: 00000000 00000000 00000000 01111111// a b: 00000000 00000000 00000000 10000010// 存到 c 中时c 只有1个字节所以只保留最后8位// c: 10000010 这是补码// 而 %d 输出的是有符号整数// 所以C又会发生整型提升c会被提升成int类型// 适用有符号整数提升是按照变量的数据类型的符号位来提升的// c: 11111111 11111111 11111111 10000010 这是补码// 11111111 11111111 11111111 10000001 这是反码// 10000000 00000000 00000000 01111110 这是原码所以最后输出的是 -126算术转换如果某个操作符的各个操作数属于不同的类型那么需将其中一个操作数的类型转换为另一个操作数的类型。如果某个操作数的类型在上面这个列表中排名靠后那么首先要转换为另外一个操作数的类型后执行运算。