zoukankan      html  css  js  c++  java
  • C语言中的按位移动及其简单引用

    C语言中的按位移动及其简单应用

    在C语言中按位左移用”<<”表示,按位右移用”>>”表示。

    按位左移和按位右移运算经常被用来替换乘二除二运算,但是要注意,这两者之间并不完全等价。下面就分析一下:

    首先明确,按位移动分为逻辑移动和算术移动,具体就是:逻辑左移、算术左移;逻辑右移、算术右移。

    算术左移、算术右移、逻辑左移、逻辑右移的操作如下图:

     

    可以看到,逻辑左移=算术左移:都是左移然后右边补零

    算术右移和逻辑右移有所区别:逻辑右移是右移并且左边补0,而算术左移是右移并且左边补1(也就是补符号位)

    C语言中:左移采用的逻辑左移(和算术左移的效果相同)和算术右移。由于算术左移和逻辑左移的效果相同,所以我们可以认为,C语言中采用的是算术移动对于有符号数而言)。

    那么算术左移、算术右移和乘二、除二运算结果是否一致呢?

    先来看左移:

    先给出结论:无论是正数还是负数,只要结果不溢出(也就是不超过取值范围)结果就是乘2。

    比如:

     

    输出为:

     

    对于结果溢出的(也就是超出取值范围的),比如:

     

    输出为:

     

    发现没,两个结果都不对,因为char是8位的,表示范围为-128~127,结果产生溢出了。那为什么会产生这样的结果呢?

    a = 65. 二进制位:0100 0001

    逻辑左移一位结果为: 1000 0010 ,我们发现,这个数的符号位变成了1,也就是负数了,就是-126。细心的人也会发现,理想结果130、实际结果 -126、27,这三者之间貌似有某种联系,的确有联系,这里就不深究了。

    再来看看右移:

    先给结论:首先,右移,并不会造成结果溢出的情况。对于正数,放心大胆地去右移吧,结果都相当于除二;但是对于负数,结果不一定相等,最好不要用右移代替除二。

    比如:对于正数

     

    输出为:

     

    结果都是正确的。

    但是对于负数,比如:

     

    输出为:

     

    可以看到对于偶数的结果是正确的。但是对于奇数,结果的绝对值比除二的结果的绝对值大1

    那么能否实现逻辑右移呢?

    上面提到了C语言中采用的是算术右移,那么有没有办法实现逻辑右移呢?可以的。

    我们需要注意一下无符号数,无符号数并没有符号位,所以对无符号数进行的位移都是逻辑位移。对于一个有符号数,如果我们想对他进行逻辑右移,那么我们可以先将该数转换成对应对的无符号数,然后再进行右移操作

    比如对于char a = -6。

    二进制位 1111 1010

    如果是算术右移,结果应该为: 1111 1101 也就是-3

    如果是逻辑右移,结果应该为: 0111 110 也就是125

    下面我们验证一下:

     

    输出为:

     

    正确

    位移运算的简单应用

    有这样一个题,要求是将一个int型的数据转换成二进制和16进制的字符串输出。

    比如对于整型量456789

    我们要输出:(空格不用了)

    00000000  00000110  11111000  01010101

    0x0006F855

     

    对于求二进制,该数在内存中就是二进制的表示,我们只需要把每一位变成字符然后存到字符数组中即可,方法就是按位与和位移相结合,比如我们想得到第一个位(最高位),那么我们可以先按位与上10000000 00000000 00000000 00000000 然后将结果按位右移31位(需要注意,应该是采用逻辑右移,而不是算术右移,也就是前面要补0,而不是补1,方法是上面提到的,先将该数转换成无符号数),就得到了第一位的值,之后转换成字符即可。

     

    对于求16进制,我们则需要以四个二进制位为一个单位,方法类似,思路就是想办法把当前要转换的四个二进制位移动到最低四位,因此我们可以用一个char来保存8位二进制,然后想办法把高四位置为0,把待转换的四位放到第四位。

    比如说,我们现在想转换标红的部分

    00000000  00000110  11111000  01010101

    应该是转换成F,那么怎么转换呢?

    首先我们先将该数左移16位,也就是4*4位,改数就变成了

    11111000  01010101 00000000 00000000

    然后我们在右移28位,也就是32-4位(特别注意,这里应该是逻辑右移,而不是算术右移,也就是要保证前面补0,而不是补1,方法就是上面提到的,先将该数转换成无符号数,然后再右移

    结果为:

    00000000 00000000 00000000 00001111

    最后在用char类型将数据的低8位截断,并转换成字符F即可。

     

    源代码如下:

    #include <stdio.h>
    
    #include <string.h>
    
    #include <stdlib.h>
    
     
    
    char *get_bin_string(int num)
    
    {
    
        unsigned int u_num = (unsigned int)num;
    
        char *buffer = (char *)malloc(33);
    
        if(buffer == NULL)
    
             return NULL;
    
        buffer[32] = '';
    
        int i = 0;
    
        for(;i < 32;i++)
    
        {
    
             unsigned int temp = u_num &(1<<(31 - i));
    
             temp = temp>>(31-i);
    
             buffer[i] = temp == 0 ? '0':'1';
    
        }
    
        return buffer;
    
    }
    
    char *get_hex_string(int num)
    
    {
    
        unsigned int u_num = (unsigned int)num;
    
        char *buffer = (char *)malloc(11);
    
        if(buffer == NULL)
    
             return NULL;
    
        //填写固定的部分
    
        buffer[0] = '0';
    
        buffer[1] = 'x';
    
        buffer[10] = '';
    
        char *temp = buffer + 2;
    
        int i = 0;
    
        for(;i < 8;i++)
    
        {
    
             unsigned int af = u_num<<(4 * i);
    
             af = af >> 28;
    
             temp[i] = (char)(u_num<<(4 * i)>>28);
    
             temp[i] = temp[i] < 10 ? temp[i] + 48 :temp[i] + 55;
    
        }
    
        return buffer;
    
    }
    
    int main()
    
    {
    
        int num = 456789;
    
        char *bin = get_bin_string(num);
    
        char *hex = get_hex_string(num);
    
        printf("二进制为:%s
    ",bin);
    
        printf("十六进制为:%s
    ",hex);
    
        free(hex);
    
        free(bin);
    
        return 0;
    
     
    
    }

     

    最后再强调一下,右移的时候一定要考虑清楚,我们是想要前面补0还是补1,也就是采用逻辑右移还是算术右移,如果是采用逻辑右移,要先将该数转换成无符号数。

     

    就到这里了。

    最后附上word文件和源代码文件

    链接:http://pan.baidu.com/s/1nuYBXjj 密码:5huf

     

    如果你觉得对你有用,请赞一个吧~~~

     

  • 相关阅读:
    URAL 1948 H
    int、long、long long取值范围
    Bonetrousle HackerRank 数学 + 思维题
    湖南省第十二届大学生计算机程序设计竞赛 problem A 2016
    Abbreviation ---- hackerrank
    POJ 3321 Apple Tree DFS序 + 树状数组
    HDU
    PICO CTF 2013 PHP 2: 85
    XSS进阶三
    XSS进阶二
  • 原文地址:https://www.cnblogs.com/qingergege/p/7427065.html
Copyright © 2011-2022 走看看