08 C各种进制、存储细节、位运算

2018-10-30  本文已影响0人  亨锅锅

1、基本理解


#include <stdio.h>

int main()
{
    /*
     *
     八进制  十六进制 错      十进制   错    十进制   十进制
     00011   0x001   0x7h4  10.98   0986  .089    -109
     十进制  错     二进制   十六进制  错  十进制  错      十进制
     +178   0b325  0b0010  0xffdc  96f 96.0f   96.oF  -.003

     在C语言中, 如果想用十六进制表示某个数, 前面需要加上0x
     在C语言中, 如果想用八进制表示某个数, 前面需要加上0
     在C语言中, 如果想用二进制表示某个数, 前面需要加上0b
     */

    // 注意点:
    // 1.%i %d代表以十进制输出整数
    // 2.0x和0X一样,0b和0B一样

//    // 用十进制来表示
//    int num1 = 12;
//    printf("num1 = %i\n", num1);
//    // 用十六进制来表示
//    int num2 = 0xc;
//    printf("num2 = %i\n", num2);
//    // 用八进制来表示
//    int num3 = 014;
//    printf("num3 = %i\n", num3);
//    // 用二进制来表示
//    int num4 = 0b1100;
//    printf("num4 = %i\n", num4);


    int num = 12;
    // 以十进制输出
    printf("%i\n", num);
    // 以八进制输出
    printf("%o\n", num);
    // 以十六进制输出
    printf("%x\n", num);
    // 以二进制输出必须自己实现(后续会讲解如何实现)
    return 0;
}

2、进制转换

#include <stdio.h>

int main()
{
    /*
     * 进制转换
     * 十进制 --> 二进制
     * 二进制 --> 八进制
     * 二进制 --> 十六进制
     */
    /*
     * 十进制 --> 二进制
     * 规则: 除2取余, 余数倒叙
     *
     *
     * 12
     *  2
     * ---
     *  6   0
     *  2
     * ---
     *  3   0
     *  2
     * ---
     *  1   1
     *  2
     * ---
     *  0   1
     *
     * 12 --> 1100
     */
    /*
     * 15
     *  2
     * ---
     *  7  1
     *  2
     * ---
     *  3  1
     *  2
     * ---
     *  1  1
     *  2
     * ---
     *  0  1
     */
    int num = 0b1111;
    printf("%i", num);
    return 0;
}

#include <stdio.h>

int main()
{
    /*
     * 进制转换
     * 十进制 --> 二进制
     * 二进制 --> 十进制
     * 二进制 --> 八进制
     * 二进制 --> 十六进制
     */
    /*
     * 十进制 --> 二进制
     * 规则: 除2取余, 余数倒叙
     *
     *
     * 12
     *  2
     * ---
     *  6   0
     *  2
     * ---
     *  3   0
     *  2
     * ---
     *  1   1
     *  2
     * ---
     *  0   1
     *
     * 12 --> 1100
     */
    /*
     * 15
     *  2
     * ---
     *  7  1
     *  2
     * ---
     *  3  1
     *  2
     * ---
     *  1  1
     *  2
     * ---
     *  0  1
     */
//    int num = 0b1111;
//    printf("%i\n", num);

    /*
     * 二进制 --> 十进制
     * 1100 --> 十进制
     * 规则: 系数 * 基数(索引)
     * 系数: 每一位对应的值就是系数
     * 基数:
     * 例如从二进制转换到十进制, 那么二就是基数
     * 例如从八进制转换到十进制, 那么八就是基数
     * 索引:从最低位以0开始, 依次递增
     *
     * 1*2(3) + 1*2(2) + 0*2(1) + 0*2(0)
     * 1        1        0        0
     * 8      + 4      + 0      + 0
     */

    /*
     * 十进制转换八进制
     * 规则: 除8取余, 余数倒叙
     *
     * 24
     *  8
     * ---
     *  3  0
     *  8
     * ---
     *  0  3
     *
     * 24 --> 30
     */
//    printf("%i\n", 030);

    /*
     * 十进制转换十六进制
     * 规则: 除16取余, 余数倒叙
     * 24
     * 16
     * ---
     *  1  8
     * 16
     * ---
     *  0  1
     *
     * 24 --> 18
     */
//    printf("%i\n", 0x18);

    /*
     * 八进制转换十进制
     * 规则: 系数 * 基数(索引)
     * 0*8(2)  +  3 * 8(1)  +    0*8(0)
     * 0          3              0
     */

    /*
     * 十六进制转换十进制
     * 规则: 系数 * 基数(索引)
     *   1*16(1) + 8*16(0)
     * 0x1         8
     */

    /*
     * 二进制转八进制
     * 必须知道的是:
     * 1.在八进制中最大的数字 7
     * 2.三个二进制位最大能表示的数字就是7
     * 1*2(2) + 1*2(1) + 1*2(0)
     * 111
     * 所以二进制在转换为八进制的时, 把三个二进制位看做一个八进制位即可
     *   1   4
     *  001 100   --> 14
     */
    // 在C语言中不看怎么存, 只看怎么取
//    printf("%o", 0b001100);

    /*
     * 二进制转十六进制
     * 必须知道的是:
     * 1.在十六进制中最大的数字 15
     * 2.四个二进制位最大能表示的数字就是15
     * 1*2(3) + 1*2(2) + 1*2(1) + 1*2(0)
     * 1111
     * 所以二进制在转换为十六进制的时, 把四个二进制位看做一个十六进制位即可
     *   3     8
     *  0011 1000   --> 0x38
     */
//    printf("%x\n", 0b111000);

    /*
     * 二进制快速转换十进制
     * 64 32 16 8 4 2 1
     * 1  1  1  1 1 1 1
     */
    return 0;
}

3、存储细节

#include <stdio.h>

int main()
{
    /*
     * 在计算机中 正整数和负整数的源码, 补码, 反码是有区别的
     */
    /*
     * 正整数的源码, 补码, 反码都是它的二进制, 三码合一
     * 12 --> 1100
     *
     * 1100 就是12的源码
     * 1100 就是12的反码
     * 1100 就是12的补码
     *
     * int类型在计算机中占用4个字节
     * 1个字节等于8位, 所以int类型总共占用32位
     *
     * 注意点: 在存储正整数的时候, 第一个(最高位)是符号位, 0代表是正数, 1代表是负数
     * 0000 0000 0000 0000 0000 0000 0000 1100
     */
//    int num = 12;

    /*
     * 负整数的源码,补码,反码
     * 源码: 二进制, 将最高位变为1
     * 1000 0000 0000 0000 0000 0000 0000 1100
     * 反码: 除了符号位以外, 0变1, 1变0
     * 1111 1111 1111 1111 1111 1111 1111 0011
     * 补码: 反码+1
     * 1111 1111 1111 1111 1111 1111 1111 0011
     * 0000 0000 0000 0000 0000 0000 0000 0001
     * ----------------------------------------
     * 1111 1111 1111 1111 1111 1111 1111 0100
     *
     * 注意点;
     * 无论是正整数还是负整数, 存储在计算机中的都是补码
     *
     *
     * 源码 -> 反码(0变1, 1变0) --> 补码(反码+1)
     * 补码 -> 反码(补码-1) -> 源码(0变1, 1变0)
     */
//    int num = -12
    /*
     * 1 + 1
     * 0000 0000 0000 0000 0000 0000 0000 0001
     * 0000 0000 0000 0000 0000 0000 0000 0001
     * ----------------------------------------
     * 0000 0000 0000 0000 0000 0000 0000 0010
     */
//    printf("%i\n", 0b00000000000000000000000000000010);
    /*
     * 1 - 1  理解为 1 + (-1)
     * 0000 0000 0000 0000 0000 0000 0000 0001 源码
     * 1000 0000 0000 0000 0000 0000 0000 0001 源码
     * ----------------------------------------
     * 1000 0000 0000 0000 0000 0000 0000 0010 错误结果
     */
//    printf("%i\n", 0b10000000000000000000000000000010);
    /*
     * 1 - 1  理解为 1 + (-1)
     * 0000 0000 0000 0000 0000 0000 0000 0001    1补码
     *
     * 1000 0000 0000 0000 0000 0000 0000 0001    -1源码
     * 1111 1111 1111 1111 1111 1111 1111 1110    -1反码
     * 0000 0000 0000 0000 0000 0000 0000 0001
     * ------------------------------------------
     * 1111 1111 1111 1111 1111 1111 1111 1111    -1补码
     *
     *
     * 0000 0000 0000 0000 0000 0000 0000 0001     1补码
     * 1111 1111 1111 1111 1111 1111 1111 1111    -1补码
     * -------------------------------------------
     * 0000 0000 0000 0000 0000 0000 0000 0000    0
     */


    /*
     * 4 - 6 --> 4 + (-6)
     * 0000 0000 0000 0000 0000 0000 0000 0100  4补码
     *
     * 1000 0000 0000 0000 0000 0000 0000 0110  -6源码
     * 1111 1111 1111 1111 1111 1111 1111 1001  -6反码
     * 0000 0000 0000 0000 0000 0000 0000 0001
     * -------------------------------------------
     * 1111 1111 1111 1111 1111 1111 1111 1010  -6补码
     *
     *
     *
     * 0000 0000 0000 0000 0000 0000 0000 0100  4补码
     * 1111 1111 1111 1111 1111 1111 1111 1010  -6补码
     * 1111 1111 1111 1111 1111 1111 1111 1110  补码的结果
     *
     * 注意点: 当前计算出来的是正确结果的补码, 要想知道正确结果是多少, 需要将补码转换为源码
     *
     * 1111 1111 1111 1111 1111 1111 1111 1110  结果的补码
     * 0000 0000 0000 0000 0000 0000 0000 0001
     * -------------------------------------------
     * 1111 1111 1111 1111 1111 1111 1111 1101  结果的反码
     * 1000 0000 0000 0000 0000 0000 0000 0010  结果的源码  -2
     */

    /*
     0101
   + 0001
     -----
     0102 --> 0110

     0110 --> 0102
   - 0001     0001
    ---------------
              0101
   */

    return 0;
}

4、位运算


#include <stdio.h>

int main()
{
    /*
     * & 按位与
     * | 按位或
     * ~ 按位取反
     * ^ 按位异或
     */

    /*
     * & 按位与
     * 规则: 一假则假
     * 在C语言中0代表假, 1代表真
     * 9 & 3 = ?
     *
     *   0000 0000 0000 0000 0000 0000 0000 1001 // 9的补码
     * & 0000 0000 0000 0000 0000 0000 0000 0011 // 3的补码
     * -----------------------------------------------
     *   0000 0000 0000 0000 0000 0000 0000 0001 // 1
     *
     * 12 & 8
     *  0000 0000 0000 0000 0000 0000 0000 1100
     *& 0000 0000 0000 0000 0000 0000 0000 1000
     * -----------------------------------------------
     *  0000 0000 0000 0000 0000 0000 0000 1000
     */
//    printf("%i\n", 9 & 3);
//    printf("%i\n", 12 & 8);

    /*
     * | 按位或
     * 规则: 一真则真
     * 9 | 3 = ?
     *  0000 0000 0000 0000 0000 0000 0000 1001 // 9的补码
     *| 0000 0000 0000 0000 0000 0000 0000 0011 // 3的补码
     *  -----------------------------------------------
     *  0000 0000 0000 0000 0000 0000 0000 1011
     */
//    printf("%i\n", 9 | 3);

    /*
     * ~ 按位取反
     * 规则: 真变假, 假变真
     * ~9 = ?
     * 0000 0000 0000 0000 0000 0000 0000 1001 // 9的补码
     *~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 // 结果的源码 -10
     */
//    printf("%i\n", ~9);

    /*
     * ^ 按位异或
     * 规则: 相同为0, 不同为1
     * 9 ^ 3 = ?
     * 0000 0000 0000 0000 0000 0000 0000 1001 // 9的补码
     *^0000 0000 0000 0000 0000 0000 0000 0011 // 3的补码
     *-------------------------------------------
     * 0000 0000 0000 0000 0000 0000 0000 1010 // 10
     */
    printf("%i\n", 9 ^ 3);
    return 0;
}

#include <stdio.h>

int main()
{

    /*
     * & 按位与
     * 规则: 一假则假
     * 规律: 任何一位和1相与, 结果还是原来的那一位
     * 0000 0000 0000 0000 0000 0000 0000 0001 // 1的补码
     *&0000 0000 0000 0000 0000 0000 0000 0001
     * -----------------------------------------
     * 0000 0000 0000 0000 0000 0000 0000 0001
     *
     * 0000 0000 0000 0000 0000 0000 0000 0000 // 0的补码
     *&0000 0000 0000 0000 0000 0000 0000 0001
     * -----------------------------------------
     * 0000 0000 0000 0000 0000 0000 0000 0000
     *
     * 0000 0000 0000 0000 0000 1011 0000 0000 // 0的补码
     *&0000 0000 0000 0000 0000 1111 0000 0000
     * -----------------------------------------
     * 0000 0000 0000 0000 0000 1011 0000 0000
     *
     */
//    int res1 = 1 & 1;
//    printf("%i\n", res1);
//    int res2 = 0 & 1;
//    printf("%i\n", res2);

    /*
     *
     * ^ 按位异或
     * 规则: 相同为0, 不同为1
     * 规律:
     * 1.任何两个相同的值异或之后的结果都是0
     * 2.任何一个数和0异或之后的结果还是那个数
     * 3.任何一个数异或另外一个数两次之后, 结果还是那个数
     */
//    int res1 = 5 ^ 5;
//    printf("%i\n", res1);
//    int res2 = 9 ^ 9;
//    printf("%i\n", res2);

//    int res1 = 5 ^ 0;
//    printf("%i\n", res1);
//    int res2 = 9 ^ 0;
//    printf("%i\n", res2);

//    int res1 = 18 ^ 5 ^ 5;
//    printf("%i\n", res1);
//    int res2 = 22 ^ 9 ^ 9;
//    printf("%i\n", res2);

    // 应用场景: 简单的加密
    int pwd = 123456789;
    int res = pwd ^ 998;
    printf("加密之前: %i\n", pwd);
    printf("加密之后: %i\n", res);
    int res2 = res ^ 998;
    printf("解密之后: %i\n", res2);
    return 0;
}

install B小案例


#include <stdio.h>
void test1();
void test2();
int main()
{
    /*
     * 需求: 要求判断用户输入的数据是奇数还是偶数
     */
    /*
//    int num = 7;
//    if(0 == (num % 2)){
//        printf("%i是偶数\n", num);
//    }else{
//        printf("%i是奇数\n", num);
//    }
    */

    /*
    int num = 12;
    // 注意点: 三目是一个运算符, 所以必须有结果
    // 也就是 结果A和结果B的位置放的必须是变量,常量, 表达式
    // 如果放的是一个函数, 那么这个函数必须有返回值
//    0 == (num % 2) ? printf("%i是偶数\n", num) : printf("%i是奇数\n", num);
//    0 == (num % 2) ? test1() : test2();

    // printf函数的返回值, 是我们打印了多少个字符
//    int res = printf("李"); // 如果放的是中文, 是2还是3不确定, 根据当前的编码方式GBK UTF-8
//    printf("res = %i\n", res);
     */


    /*
     * 8 偶数
     *   1000
     * & 0001
     * -------
     *   0000  --> 0
     *
     * 12 偶数
     *   1100
     * & 0001
     * -------
     *   0000  --> 0
     *
     *
     * 9 奇数
     *   1001
     * & 0001
     * -------
     *   0001  --> 1
     *
     * 13 奇数
     *   1101
     * & 0001
     * -------
     *   0001  --> 1
     */

    int num = 4;
//    if(1 == (num & 1)){
//        printf("%i是奇数\n", num);
//    }else{
//        printf("%i是偶数\n", num);
//    }

    if(num & 1){
        printf("%i是奇数\n", num);
    }else{
        printf("%i是偶数\n", num);
    }

    return 0;
}
void test1(){
    printf("test1\n");
}
void test2(){
    printf("test2\n");
}

#include <stdio.h>

int main()
{
    /*
     * << 左移
     * >> 右移
     */
    /*
      9 << 1
      0000 0000 0000 0000 0000 0000 0000 0000 // 位置参考
      000 0000 0000 0000 0000 0000 0000 10010 // 9的补码

      9 << 2
      0000 0000 0000 0000 0000 0000 0000 0000 // 位置参考
      00 0000 0000 0000 0000 0000 0000 100100// 9的补码

      移动规则: 从符号位开始整体移动, 多余的砍掉, 缺少的用零补
      计算规律: 一个数左移几位就是 这个数乘以2的多少次幂
      9 * 2(1) = 18
      9 * 2(2) = 36
      应用场景: 在企业开发中一旦想要某个数乘以2的多少次幂, 就要想到左移
     */
//    printf("%i\n", 9 << 1);
//    printf("%i\n", 9 << 2);

    /*
     0000 0000 0000 0000 0000 0000 0000 0000 // 位置参考
     00000 0000 0000 0000 0000 0000 0010 010


     0000 0000 0000 0000 0000 0000 0000 0000 // 位置参考
     000000 0000 0000 0000 0000 0000 0010 01


     移动规则: 除符号位以外整体右移, 多出来的砍掉, 缺少的用符号位填充
     计算规则: 一个数右移几位就是 这个数除以2的多少次幂

     36 / 2(1) = 18
     36 / 2(2) = 9
     应用场景: 在企业开发中一旦想要某个数除以2的多少次幂, 就要想到右移
     */
//    printf("%i\n", 36 >> 1);
//    printf("%i\n", 36 >> 2);

    /*
     0000 0000 0000 0000 0000 0000 0000 0000 // 位置参考
     00000 0000 0000 0000 0000 0000 0000 100  --> 4
     */
    printf("%i\n", 9 >> 1);
    /*
     * 1000 0000 0000 0000 0000 0000 0000 1001 // -9源码
     * 1111 1111 1111 1111 1111 1111 1111 0110 // -9反码
     * 1111 1111 1111 1111 1111 1111 1111 0111 // -9补码
     *
     0000 0000 0000 0000 0000 0000 0000 0000 // 位置参考
     11111 1111 1111 1111 1111 1111 1111 011 // 右移完毕的结果, 补码
     0000 0000 0000 0000 0000 0000 0000 0001
     11111 1111 1111 1111 1111 1111 1111 010 // 右移完毕的结果, 反码
     10000 0000 0000 0000 0000 0000 0000 101 // 右移完毕的结果, 源码
     */
    printf("%i\n", -9 >> 1);
//    printf("%i\n", -9 / 2);


    return 0;
}

#include <stdio.h>

int main()
{
    /*
     * 要求将用户输入的整数, 以二进制的形式输出
     * 0000 0000 0000 0000 0000 0000 0000 1001
     * 0000 0000 0000 0000 0000 0000 0000 0001
     */

    int num = 9;
//    int temp = (num >> 3) & 1;
//    printf("temp = %i\n", temp);
//    temp = (num >> 2) & 1;
//    printf("temp = %i\n", temp);
//    temp = (num >> 1) & 1;
//    printf("temp = %i\n", temp);
//    temp = (num >> 0) & 1;
//    printf("temp = %i\n", temp);

//    for(int i = 0; i < 32; i++){
//        int temp = (num >> 31 - i) & 1;
//        printf("%i", temp);
//    }

    char ch = 'a';
//    printBinary(num);
      printBinary(ch);
      printf("%i\n", 0b01100001);

    return 0;
}
void printBinary(char value){
    // int 4 --> 32
    // char 1 --> 8
    // 在企业开发中 , 数字我们称之为魔鬼
    int len = sizeof(value) * 8;
    for(int i = 0; i < len; i++){
        int temp = (value >> (len - 1 - i)) & 1;
        printf("%i", temp);
        if(((i+ 1) % 4) == 0){
            printf(" ");
        }
    }
    printf("\n");
}

#include <stdio.h>

int main()
{
    /*
     * 需求: 交换两个变量的值
     *
     * int a = 10; int b = 20;
     */

    int a = 10;
    int b = 20;
    printf("交换之前a = %i, b = %i\n", a, b);
//    int temp = a;
//    a = b;
//    b = temp;
//    printf("交换之后a = %i, b = %i\n", a, b);

//    a = a + b; // a = 10 + 20; a = 30;
//    b = a - b; // b = 30 - 20; b = 10;
//    a = a - b; // a = 30 - 10; a = 20;
//    printf("交换之后a = %i, b = %i\n", a, b);

//    a = a ^ b;
//    b = a ^ b; // b = a ^ (b ^ b);  b = 10;
//    a = a ^ b; // a = (a ^ a) ^ b ; a = 20;

     b = a ^ b;
     a = a ^ b; // a = a ^ a ^ b; a = b;  a = 20;
     b = a ^ b; // b = a ^ b ^ b; b = a;  a = 10;
    printf("交换之后a = %i, b = %i\n", a, b);
    return 0;
}

#include <stdio.h>

int main()
{
    /*
     * 变量的内存分析
     * 1.内存是连续的
     * 2.内存地址从打到小
     * 3.计算机会从内存地址大的开始分配内存(内存寻址从大到小)
     * 也就是说先定义的变量内存地址大于后定义的变量
     *
     */
    /*
     * 0000 0000 0000 0000 0000 0000 0000 1001 // 补码
     *
     * 规则: 由于内存寻址是从大到小, 所以存储补码也是从大到小(也就是从高位开始存储)
     */
    int num1 = 9;
    int num2 = 7;
    printf("num1 %p\n", &num1);
    printf("num2 %p\n", &num2);

    char *ch = &num1;
    for(int i = 0; i < 4; i++){
        printf("%i\n", ch[i]);
    }
    printf("%p\n", ch++);
    printf("%p\n", ch++);
    printf("%p\n", ch++);
    printf("%p\n", ch++);
    return 0;
}
上一篇下一篇

猜你喜欢

热点阅读