源码补码反码
- int main(int argc, const char * argv[])
- {
- // int 占 4 个字节 1 个字节 8 位
- int num = 12;
- /*// 12 的二进制
- 12 在内存中存储的是它的补码
- 00000000 00000000 00000000 00001100
- 正数的特点:(三码合一) 正数的原码就是 TA 的反码就是 TA 的补码
- -12
- 二进制的最高位我们称之为符号位
- 如果符号位是 0 代表是一个正数,
- 如果符号位是 1 代表是一个负数
- 10000000 00000000 00000000 00001100 (-12 的原码)
- 11111111 11111111 11111111 11110011(反码, 符号位不变其它位取反)
- 11111111 11111111 11111111 11110011
- +00000000 00000000 00000000 00000001
- _____________________________________________
- 11111111 11111111 11111111 11110100(补码 , 反码 + 1)
- 结论: 无论正数负数在内存中存储的都是补码
- 11111111 11111111 11111111 11110101 (补码)
- -00000000 00000000 00000000 00000001 (-1)
- _____________________________________________
- 11111111 11111111 11111111 11110100 (反码)
- 10000000 00000000 00000000 00001011
- */
- printf("%d\n", 0b11111111111111111111111111110101);
- return 0;
- }
位运算
- /*
- 位运算都是针对二进制的
- &
- |
- ^
- ~
- <<>>
- */
- int main(int argc, const char * argv[])
- {
- /*
- & 按位与
- 特点: 只有对应的两位都是 1 才返回 1 否则返回 0
- 口诀: 一假则假
- 规律: 任何数按位与上 1 结果还是那个数
- 1001
- & 0101
- _______
- 0001
- 1001
- &1111
- ______
- 1001
- */
- /*
- | 按位或
- 特点: 只要对应的两位其中一位是 1 就返回 1
- 口诀: 一真则真
- 1001
- | 0101
- ________
- 1101
- */
- /*
- ^ 按位异或
- 特点: 对应的两位不相同返回 1 相同返回 0
- 1001
- ^ 0101
- _______
- 1100
- // 多个整数按位异或的结果和顺序无关
- 1001
- ^ 0101
- _______
- 1100
- 1100
- ^ 0110
- _______
- 1010
- 1001
- ^ 0110
- _______
- 1111
- 1111
- ^ 0101
- _______
- 1010
- // 相同整数按位异或结果是 0
- 1001
- ^ 1001
- _______
- 0000
- // 任何整数按位异或上 0 结果不变
- 1001
- ^ 0000
- _______
- 1001
- // 任何整数按位异或上另一个整数两次结果还是那个数
- 1001
- ^ 1001
- ____________
- 0000
- 0000
- ^0101
- ______
- 0101
- */
- // int result = 9 & 5;
- // int result = 9 | 5;
- // int result = 9 ^ 5;
- // 多个整数按位异或的结果和顺序无关
- // int result2 = 9 ^ 5 ^ 6;
- // int result2 = 9 ^ 6 ^ 5;
- // 相同整数按位异或结果是 0
- // int result3 = 9 ^ 9;
- // 任何整数按位异或上 0 结果不变
- // int result4 = 9 ^ 0 ;
- // 任何整数按位异或上另一个整数两次结果还是那个数
- // int result5 = 9 ^ 9 ^ 5;
- // int result6 = 9 ^ 5 ^ 9;
- // printf("result = %d\n", result6);
- /*
- ~ 按位取反
- 特点: 0 变 1 1 变 0
- 0000 0000 0000 0000 0000 0000 0000 1001
- ~1111 1111 1111 1111 1111 1111 1111 0110 (补码)
- 0000 0000 0000 0000 0000 0000 0000 0001
- ______________________________________________
- 1111 1111 1111 1111 1111 1111 1111 0101 (反码)
- 1000 0000 0000 0000 0000 0000 0000 1010
- */
- // int result = ~9;
- //// printf("result = %d\n", result);
- // printf("%d\n",0b11111111111111111111111111110110);
- return 0;
- }
左移右移
- int main(int argc, const char * argv[]) {
- /*
- << 左移
- a << n 把整数 a 的二进制位往左边移 n 位
- 移出的位砍掉, 低位补 0, 发现左移会把原有的数值变大
- 9 << 1 = 18 9 * 2(1) = 18
- 9 << 2 = 36 9 * 2(2) = 26
- 9 << n = 9 * 2(n)
- 左移的应用场景: 当要计算某个数乘以 2 的 n 次方的时候就用左移, 效率最高
- 0000 0000 0000 0000 0000 0000 0000 0000
- 100 0000 0000 0000 0000 0000 0000 10010
- 注意点: 左移有可能改变数值的正负性
- */
- /*
- >> 右移
- a>> n 把整数 a 的二进制位往右边移 n 位
- 移出的位砍掉, 缺少的以为最高位是 0 就补 0 是 1 就补 1(是在当前操作系统下)
- 9>> 1 = 4 9 / 2(1) = 4
- 9>> 2 = 2 9 / 2(2) = 2
- 右移的应用场景: 当要计算某个数除以 2 的 N 次方的时候就用右移, 效率最高
- 0000 0000 0000 0000 0000 0000 0000 0000
- 000000 0000 0000 0000 0000 0000 0000 10
- */
- // int result = 9 <<2;
- int result = 9>> 2;
- printf("result = %d\n", result);
- return 0;
- }
变量存储细节
- int main(int argc, const char * argv[]) {
- // 变量为什么要有类型? 每种类型占用的内存空间不一样 int 4, char 1 double 8
- // 只要定义变量, 系统就会开辟一块存储空间给我们的变量存储数据, 内存寻址是从大到小
- // 越先定义的变量, 内存地址越大
- // 变量的地址就是所占的存储空间最小的字节地址
- int num;
- // 注意: 由于内存寻址是从大到小, 所以存储数据也是从大到小的存储 (先存储二进制的高位, 再存储低位)
- // 高位 --> 低位
- // 00000000 00000000 00000000 00001001
- num = 9; // 9 --> 二进制 --> 存储 (补码)
- int value;
- value = 600; //00000000 00000000 00000010 01011000
- // %p 是输出地址
- // & 变量名称, 是取出变量的地址
- printf("num = %p\n", &num);
- printf("value = %p\n", &value);
- // 获取存储的每一位
- char *c = &value;
- for (int i = 0; i < sizeof(num); i++) {
- int result = c[i]; // 取出每个字节中存储的数据
- printf("%i\n", result);
- }
- return 0;
- }
来源: http://www.jianshu.com/p/4229c99d0306