c11---位运算相关

Posted 672530440

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c11---位运算相关相关的知识,希望对你有一定的参考价值。

//
//  main.c
//  03-原码反码补码

#include <stdio.h>

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;
}
//
//  main.c
//  01-进制
#include <stdio.h>

int main(int argc, const char * argv[])
{
//     1.默认就是10进制
    int num = 12;
//    2.在前面加上一个0就代表八进制
    int num1 = 014;
    
//    %d是以十进制的方式输出一个整数
    printf("%d\n", num1);
//    %o是以八进制的方式输出一个整数
    printf("%o\n", num);
    
//    在数值前面加上0b就代表二进制
    int num2 = 0b1100;
    printf("%d\n", num2);
//    在数值前面加上0x就代表十六进制
    int num3 = 0xc;
    printf("%d\n", num3);
//     %x是以十六进制的方式输出一个整数
    printf("%x\n", num);
    
//     口诀:不看你怎么存,只看你怎去取
    
    return 0;
}
//
//  main.c
//  02-进制转换

#include <stdio.h>

int main(int argc, const char * argv[])
{

    /*
     十进制  -> 二进制
     9
     转换原理:除2取余 倒序读取
     
     
     9/2  4  1
     4/2  2  0
     2/2  1  0
     1/2  0  1
     
     9 --> 1001
     
     
     二进制 --> 十进制
     1001
     转换原理:乘以2的幂数(幂数从0开始), 然后相加
     
     1 * 2(0) = 1
     0 * 2(1) = 0
     0 * 2(2) = 0
     1 * 2(3) = 8
     
     1 + 0 + 0 + 8 = 9
     
    1 1 1  1 1
   16 8 4  2 1

     
     N位二进制的取值范围
     1位  取值范围 0~1  0~2的1次方-1
     2位  取值范围 0~3  0~2的2次方-1
     3位  取值范围 0~7  0~2的3次方-1
     n位  取值范围  0~2(n)-1
     
     000
     001
     010
     011
     100
     101
     110
     111
     
     
     11111 0~ (32-1)
     
     
     二进制转换为八进制  进制越大表示的位数就越短
     规律:三个二进制位代表一个八进制位  
     因为3位的最大取值是7 而八进制是逢八进一
     
     1个字节 8位
     000   0
     001   1
     100   4
     
     014

     
     二进制转换为十六进制
     规律:四个二进制位代表一个十六进制位
     因为4位的最大取值是15, 而十六进制是逢十六进一
     
     0000 0
     1100 c
     
     0xc
     
     */
    printf("%d\n", 0b1001);
    
    return 0;
}
//
//  main.c
//  05-位运算

#include <stdio.h>
/*
 位运算都是针对二进制的
 &
 |
 ^
  ~
 
 
 <<
 >>
 */
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;
    
}
//
//  main.c
//  位运算符2
//
//  Created by xiaomage on 15/6/9.
//  Copyright (c) 2015年 itcast. All rights reserved.
//

#include <stdio.h>

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;
}
//
//  main.c
//  位运算符练习1
//
//  Created by xiaomage on 15/6/9.
//  Copyright (c) 2015年 itcast. All rights reserved.
//

#include <stdio.h>

void printBinay(int value);

int main(int argc, const char * argv[]) {
    /*
     要求定义一个函数, 传入一个整数, 输出该整数的二进制
     %i %o %x
     
     0000 0000 0000 0000 0000 0000 0000 1001
    &0000 0000 0000 0000 0000 0000 0000 0001
     
     // 1.让9的二进制向右移31, 就可以获取到9得最高位的二进制, 然后让9的二进制的最高位和1相&, 那么就可以获得9的最高位
     // 2.让9的二进制向右移30, 就可以获得9二进制的第二位
     // 3.以此类推, 直到0位置
     
     技巧:
     1.任何数与1相&都是那个数
     2.利用位移取出每一位
     */
    int num = 15;
    printBinay(num);
    return 0;
}
void printBinay(int value)
{
    // 1.定义变量需要向右移动的位数
    int offset = 31;
    // 2.通过循环取出每一位
    while (offset >=0) {
        int result  = (value >> offset) & 1;
        printf("%i", result);
        // 3.每次取出一位就让控制右移的变量-1
        offset--;
        if ((offset+1) % 4 == 0) {
            printf(" ");
        }
    }
    printf("\n");
}
//
//  main.c
//  位运算符练习2

#include <stdio.h>

int main(int argc, const char * argv[]) {
    // 利用位运算符, 判断一个数的奇偶性
    int num = 9;
    
    // 开发中常用的方式
    if (num % 2 == 0) {
        printf("偶数\n");
    }else
    {
        printf("奇数\n");
    }
    
    // 注意: 三目(三元)运算符, 的结果A和结果B如果是表达式, 那么必须有返回值
    (num % 2 == 0) ? printf("偶数\n"):printf("奇数\n");
    
    int length = printf("");
    printf("------%i\n", length);
    
    
    /*
     1001 9
     1011 11
     
     1010 10
     1100 12
     通过观察, 我们发现如果是偶数, 那么二进制的最后一位是0, 如果是奇数那么二进制的最后一位是1
     */
    /*
    if ((num & 1) == 1)
    {
        printf("奇数\n");
    }else
    {
        printf("偶数\n");
    }
     */
    
    if ((num & 1))
    {
        printf("奇数\n");
    }else
    {
        printf("偶数\n");
    }
    return 0;
}
//
//  main.c
//  变量的存储细节
//
//  Created by xiaomage on 15/6/9.
//  Copyright (c) 2015年 itcast. All rights reserved.
//

#include <stdio.h>

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;
}
//
//  main.c
//  char基本概念
//
//  Created by xiaomage on 15/6/9.
//  Copyright (c) 2015年 itcast. All rights reserved.
//

#include <stdio.h>

int main(int argc, const char * argv[]) {
    
    
    // 研究的问题: char类型的变量在内存中是如何存储的?
    // char 1个字节
    int num;
    char charValue;
    charValue = a; // 计算机智能识别0和1
    // a == 97 == 01100001
    int size = sizeof(charValue);
    printf("%i\n", size);
    printf("num = %p\n", &num);
    printf("char = %p\n", &charValue);
    
    // 在C语言中, 不看怎么存, 只看怎么取
    printf("%c\n", charValue);
    printf("%i\n", charValue);
    
     字符6和数字6就是完全不相同的两个数
    char c1 = 6; // 00000110
    char c2 = 6;// 00110110
    
    printf("%i\n", c1);
    printf("%i\n", c2);
    
    
    // char类型在某些情况下可以当做整型来用
    // 如果对内存要求特别严格, 而且需要存储的整数不超过char类型的取值范围, 那么就可以使用char类型来代替int类型
    // -2(7)~2(7)-1   == -128 ~ 127
    char c = 129; // 1000 0000
    printf("%i\n", c);
    
    return 0;
}
//
//  main.c
//  类型说明符

#include <stdio.h>
/*
 类型说明符:
 1.说明长度的(它可以用于修改类型所占用的存储空间的大小)
 short; short == short int  == 2个字节 == %hi/ %hd
 long; long == long int  == 8个字节 == %li / %ld
 long long; == long long int  == 8个字节 == %lli / %lld
 
 用于说明数据类型, 一般情况下和int配合使用
 
 2.说明符号位(它可以用于修改符号位是否用于正负数)
 unsigned; 无符号 , 取值正数和零 == %u
 signed; 有符号, 默认就是有符号 , 取值 正数和零以及负数
 
 3.不同类型的说明符可以混合使用
 unsigned short
 signed long
 // 注意: 相同类型不能在一起使用
 unsigned signed
 */
int main(int argc, const char * argv[]) {
    
    // int  == 4个字节 == -2(31)~2(31)-1
    
    int num = 12345678901;
    printf("num = %i\n", num);
    
    
    // int == 4个字节, long int == 8个字节 == -2(63)~2(63)-1
    long int num1 = 12345678901;
    printf("num1 = %li\n", num1);
    
    // long int == long
    // 用%li 或者 %ld来输出long类型的数据
    // C语言中不看怎么存, 只看怎么取
    long num2 = 12345678901;
    printf("num2 = %li\n", num2);
    
    // long long
    // 在64位变一下, 基本没区别, 但是如果是在32位就有区别
    // 32位下long占4个字节, long long 占8个字节
    // 注意: 如果使用long long修饰变量, 那么输出的时候需要使用%lli或者%lld
    long long int num3 = 12345678901;
    printf("num3 = %lli\n", num3);
    
    printf("long long  = %i, long  = %i\n", sizeof(num3), sizeof(num2));
    
    // long long int == long long
    long long num4 = 12345678901;
    printf("num4 = %lli\n", num4);
    
    
    
    // int == 4个字节 == -2(31)~2(31)-1
    int num = 9; // 0000 1001
    printf("num = %i\n", num);
    
    // 如果以后需要保存的数据的取值范围没有超过short int的取值范围, 可以使用short int来保存
    // 但是在企业级开发中很少使用
    // short int == 2个字节 == -2(15)~2(15)-1
    short int num1 = 9;
    printf("num1 = %i\n", num1);
    
    // short int == short
    // 如果要输出short int类型的数据, 可以使用%hi或者%hd
    short num2 = 9;
    printf("num2 = %hi\n", num2);
    
    printf("short = %i, int = %i\n", sizeof(num1), sizeof(num));
    
    
    // signed 有符号
    // 如果给变量加上修饰符signed, 代表当前变量的取值可以是正数 / 负数/ 零
    // 如果给变量加上修饰符signed, 就代表把二进制的最高位作为符号位
    // 而且默认情况下所有变量都是有符号的(signed)
    signed int num = 0;  // 正数 / 负数/ 零 int == -2(31)~2(31)-1
    printf("num = %i\n", num);
    
    // unsigned 代表无符号. 无符号就代表当前变量的取值只能是正数 / 零
    // 如果给变量加上修饰符unsigned, 就代表"不"把二进制的最高位作为符号位

    // 如果想打印无符号的变量, 只能用%u
    unsigned int num1 = -12;
    printf("num1 = %u", num1);
    
    
    // 不同类型的说明符可以混合使用
    unsigned long int num = 99;
    printf("num = %lu\n", num);
    
    signed short int num1 = 23;
    printf("num1 = %hi\n", num1);
    
    // 注意: 相同类型的说明符不能同时在一起使用
//    short long int num2 = 998;
//    unsigned signed  int num3 = 998;
    
    return 0;
}

 

以上是关于c11---位运算相关的主要内容,如果未能解决你的问题,请参考以下文章

这行代码是什么意思(按位运算符)

c语言位运算问题?

在matlab中如何进行位运算

C语言,哪位好心的大哥,姐姐:能告述我位运算吗?我看不懂啊!

C程序设计之位运算

位运算之 C 与或非异或