【问题标题】:How to extract specific bits from a number in C?如何从C中的数字中提取特定位?
【发布时间】:2012-04-10 14:05:27
【问题描述】:

我需要在 C 中提取 short 数据类型的特定部分(位数)。

例如,我有一个二进制 52504 作为 11001101000 11000,我想要前 6 位(FROM LSB --> MSB 即 011000 十进制 24)位和其余 10 位(11001101000 十进制 820)。

同样,我希望这个函数过于笼统,无法提取给定“开始”和“结束”的特定位数(即与一些十进制值等效的位块)。

我查看了其他帖子,但这些帖子没有帮助,因为给定的功能并没有太笼统。

我需要适用于 C 的 short 数据类型的东西。

编辑

我有一个大小为 2048 字节的短数组。其中每个像素为 10 位。所以我的 16 位由每个字节组成,有时占用 2 个像素数据,有时是 3 个像素数据。

喜欢

(像素:0,1) 10 位 + 6 位

然后(像素:1,2,3) 4 BITS(第一个像素剩余位)+ 10 BITS + 2 BITS。

等等……这种模式还在继续…… 所以,我只想提取每个像素并制作一个完整的数组,让每个像素完全占据整个字节(16位),比如...... 1 个字节应包含 1 个 DATA PIXEL,另一个 BYTE 应包含整个 16 位的其他 PIXEL 值,依此类推。

【问题讨论】:

  • 只屏蔽你想要的,即num & 0000000000111111,或者如果你想要另一端(num & 1111111111000000) >> 6
  • @hexa:你可能是对的,但这个问题是一个建设性的问题。该怎么办...?怎么办……?
  • 你能把这个问题说得更具体一点吗?首先你说你想把这两个数字分成两部分,然后你说你想指定一个开始和结束,这是否意味着你想要三个数字?顶部、中间和底部?
  • 实际上我正在处理 2048 大小的巨大数组,其中包含从相机拍摄的图像的某些像素的特定值。看看编辑
  • C 类型不保证大小。 short 可能有 18 位或 32 位或任何符合 C 标准的值。你需要指定一个具体的大小,或者使用 uint8_t 等大小的 int...

标签: c bit-manipulation bit bit-shift


【解决方案1】:

您需要了解两个构建块才能自己构建它:

  • 获取N 最低有效位需要构造一个位掩码,末尾带有N。你这样做:((1 << N)-1)1 << N2 ^ N:它在 N+1st 位置有一个 1,后面是全零。减去一个即可得到所需的掩码。
  • 删除M 最低有效位是一个简单的右移:k >> M

现在,您从M 剪切到N 的算法变成了一个两步过程:将原始值M 向右移动位,然后使用掩码按位执行AND N-M 个。

#define LAST(k,n) ((k) & ((1<<(n))-1))
#define MID(k,m,n) LAST((k)>>(m),((n)-(m)))

int main() {
    int a = 0xdeadbeef;
    printf("%x\n",  MID(a,4,16));
    return 0;
}

此片段将位从 4(含)剪切到 16(独占),并在运行时打印 bee。位从零开始编号。

【讨论】:

    【解决方案2】:
    unsigned short extract(unsigned short value, int begin, int end)
    {
        unsigned short mask = (1 << (end - begin)) - 1;
        return (value >> begin) & mask;
    }
    

    注意[begin, end) 是半开区间。

    【讨论】:

      【解决方案3】:

      可以这样做:

      mask = ~(~0 << (end - start + 1));
      value = (n >> start) & mask;
      

      其中n 是原始整数,value 是提取的位。

      mask 是这样构造的:

      1. ~0 = 1111 1111 1111 1111 1111 1111 1111 1111
      2. ~0 << (end - start + 1) = 1111 1111 1111 1111 1100 0000 0000 0000
         // assuming we are extracting 14 bits, the +1 is added for inclusive selection
         // ensure that end >= start
      3. ~(~0 << (end - start + 1)) = 0000 0000 0000 0000 0011 1111 1111 1111
      

      现在n 右移start 位以将所需位对齐到左侧。 然后按位 AND 给出结果。

      【讨论】:

      • 返回错误值..例如..我没有 150 并且它的二进制是 0000000010010110 ..我需要从开始(2--5)位..他们总结为 22 。但这根本不起作用。
      • @Usman 22 是最右边的 5 位...你做对了吗?
      • 是的,当然,要么你选择前 5 位,要么从第 2 位开始到第 6 位,正如我之前所说的那样......它最多计数 22。所以,我给了 start = 1 和 end = 5 或者你可以给它 end = 6...它必须是 22。但它不返回 22,而是在 start = 1 和 end = 5 时返回 11。
      • 我不明白..我只需要二进制位的特定部分..我想我已经编辑了帖子以使其更清楚..:-)
      • @Usman 但是位 2 到 5 怎么会变成 22?我也不明白这一点。第 2 到 5 位是0101,对吧? 0000000010[0101]10
      【解决方案4】:
      //To get value from specific position 'pos' to 'pos+offset' in number 'value'
      
      #define bitGet(value, offset, pos) (((1ull << offset) - 1) & (value >> (pos - 1)))
      
      //Set value 'newval' from position 'pos' to 'pos+offset' in number 'value'
      
      #define bitSet(value, offset, pos, newval)  \
      (~(((1ull << offset) - 1) << (pos - 1)) & value) | ((((1ull << offset) - 1) & newval) << (pos - 1))
      

      【讨论】:

        【解决方案5】:

        虽然这是一个非常古老的问题,但我想添加一个不同的解决方案。使用宏,

        /* 这里, startBit : 起始位位置(从 LSB 开始计数) endBit:结束位位置(从 LSB 开始计数)。注意:endBit>startBit number : 从中提取位的数字 maxLength:数字的总比特大小。 */ `

        #include <stdio.h>
        #define getnbits(startBit,endBit,number,maxLength) \
          ( number &  ( (~0U >> (maxLength-endBit)) & (~0U << startBit) )  ) 
        
        int main()
        {
            unsigned int num=255;
            unsigned int start=1,end=5,size=sizeof(num)*8;
        
            printf("Inputs : %d %d %d %d \n ",start,end,num,size);
            printf("Input number : %d\n",num);
        
            if(end>start)
            {
                int result = getnbits(start,end,num,size-1);
                printf("Output : %u\n\n",result);
            }
            else
                printf("Error : EndBit is smaller than starBit!\n\n");
        
            return 0;
        }
        

        `

        输出: 输入:1 5 255 32
        输入号码:255
        输出:62

        这里,255 = 11111111 和 62 = 00111110

        【讨论】:

          【解决方案6】:
          void  f(short int last, short int first, short int myNr){
                //construct mask for last bits
                short int mask=0;
                for(int i=0;i<last;i++)
                 { mask+=1;
                  mask<<1;}
                short int aux= myNr;
                aux=aux&mask; // only last bits are left
                //construct mask for first bits
                mask=0;
                for(int i=0;i<first;i++)
                 { mask+=0x8000h;
                  mask>>1;} 
                aux=myNr;  
                aux&=mask;
                aux>>last; // only first bits are left and shifted
          }
          

          您可以添加参数以获取值或其他内容

          【讨论】:

            【解决方案7】:
            // This is the main project file for VC++ application project 
            // generated using an Application Wizard.
            
            #include "stdafx.h"
            
            #using <mscorlib.dll>
            
            using namespace System;
            
            
            void fun2(int *parr)
            {
                printf(" size of array is %d\n",sizeof(parr));
            }
            void fun1(void)
            {
                int arr[100];
                printf(" size of array is %d\n",sizeof(arr));
                fun2(arr);
            }
            
            int extractBit(int byte, int pos) 
            {
                if( !((pos >= 0) && (pos < 16)) )
                {
                    return 0;
                }
                return ( ( byte & (1<<pos) ) >> pos);
            }
            int extractBitRange(int byte, int startingPos, int offset) 
            {
            
            
               if(  !(((startingPos + offset) >= 0) && ( (startingPos + offset) < 16)) )
               {
                    return 0;
               }
               return ( byte >> startingPos ) & ~(0xff << (offset + 1));
            }
            
            int _tmain()
            {
                // TODO: Please replace the sample code below with your own.
            
                int value;
                signed int res,bit;
                signed int stPos, len;
                value = 0x1155;
                printf("%x\n",value);
                //Console::WriteLine("Hello World");
                //fun1();
                for(bit=15;bit>=0;bit--)
                {
                    res =extractBit(value,bit);
                    printf("%d",res);
                }
                stPos = 4;
                len = 5;
                res = extractBitRange(value, stPos, len);
                printf("\n%x",res);
            
                return 0;
            }
            

            【讨论】:

              【解决方案8】:
              unsigned int extract_n2mbits(unsigned int x, int n, int m)
              {
              unsigned int mask, tmp;
              if (n < m) {
                  n = n + m;
                  m = n - m;
                  n = n - m;
              }
              mask = 1 << (n - m + 1);
              tmp = m;
              while (tmp > 1) {
                  mask = mask << 1 | 1 << (n - m + 1);
                  tmp = tmp - 1;
              }
              return ((x & mask) >> (n - m + 1));
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2021-10-31
                • 2011-07-03
                • 1970-01-01
                • 1970-01-01
                • 2019-12-10
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多