【问题标题】:Parsing a bit field parameter, how to "discard" bits in an unsigned long?解析位字段参数,如何“丢弃”无符号长字节中的位?
【发布时间】:2010-01-08 00:11:28
【问题描述】:

首先,我想知道这是否可能:假设我有一个 unsigned long 包含一些 abritrary unsigned shorts,它可能在数字中,也可能不在数字中。例如:

unsigned short int id1 = 3456,
                   id2 = 30998;

unsigned long long bitfld = id1|id2;

其他2个字段可以假设为0吗? OR 是正确的操作吗?之后,假设我将 bitfld 作为参数传递:

void dostuff (unsigned long long bf)
{
     //pseudo code
     if( the first field exists in bf)
         get first field;

     if( the second field exists in bf)
         get second field;

     //etc...
}

我想我必须轮询位域的前 16 位并检查它们,然后递归轮询它们,验证它们并在它们大于 0 时存储它们。但我不知道该怎么做,位shift 只向左或向右移动,因此,它只向右除或乘?


对不起。感谢大家的回答,但我最终使用了一种更简单、更有效的方法,一种内部结构。你看,我可以用一个字符串轻松地做到这一点,但我的目的是对代码的用户透明,可以这么说很容易编程。 我创建了一个内部结构来保存我的值,然后创建一个公共方法来创建和返回这种结构,因此它易于使用且解析速度更快(尽管它具有在堆栈中分配一个(尽管很小)结构的开销,它位域解决方案没有,但唉)。

谢谢大家的回答。

【问题讨论】:

  • 运行测试不会花很长时间。
  • 您是否有理由不能使用unsigned int 执行按位运算?
  • 你很早就失去了我。一个可能不是是数字的任意short?衣服?
  • nobugz, "这可能是也可能不是这个数字"

标签: c++ c bit-manipulation parameter-passing bit-fields


【解决方案1】:

short int 是 2 个字节长,但 long long 是 8 个字节,所以你有某种长度不匹配; 你的意思可能是这样的:

unsigned long long bitfld = id1|(id2<<16);

您可以检查ANDing 它是否占用了一个字段,例如:

void dostuff (unsigned long long bf)
{
     //pseudo code
     if(bf & 0xFFFF)
         return bf & 0xFFFF;

     if(bf & 0xFF00)
         return (bf & 0xFFFF0000) >> 32;

 //etc...
}

【讨论】:

  • 在短路的情况下,位掩码必须分别为 0xffff 和 0xffff0000,0xff 和 0xff00 分别只屏蔽一个字节。
  • 在使用按位或之前必须清除该位置的位。否则会发生与先前位的良好合并。需要很长时间才能调试和查找的东西。
【解决方案2】:

按位或运算不是您想要的。该操作会将现有位与新位合并。您需要一个替换位的操作。

首先,您需要使用 AND 和 NOT 清除位:

unsigned short int id1 = 3456,
                   id2 = 30998;

unsigned long long bitfld;

unsigned short int all_ones = ~0;
const unsigned int id2_position = 1;
const unsigned int bits_to_shift_left = id2_position * sizeof(unsigned short) * CHAR_BIT;
unsigned long long mask = ~(all_ones << bits_to_shift_left);
bitfld = bitfld & mask; // Erase all bits in id2 position
bitfld = bitfld | (id2 << bits_to_shift_left); // Put value into second position.

除非内存空间不足是个问题,否则这种位打包不值得开发工作、验证时间和额外的执行时间。将值放入 unsigned char 的“打包”缓冲区中,然后将缓冲区与 I/O 一起使用。

【讨论】:

    【解决方案3】:

    您可能应该查看位移运算符及其工作原理。如果你只是这样做: id1 | id2,你基本上把所有的东西都混在一起了。以后您将无法单独提取这些值。正如用户 alemjerus 所指出的,您想要做的类似于 id1 | (id2 &lt;&lt; 16)

    实现相同目标的另一种方法是使用联合:

    
       struct s_btfld {
           unsigned short int f1;
           unsigned short int f2;
           unsigned short int f3;
           unsigned short int f4;
       };
    
       union u_btfld {
           struct s_btfld     fields;
           unsigned long long value;
       };
    

    现在你可以这样做了:

    
       unsigned short int id1 = 3456, id2 = 30998;
    
       union u_btfld bitfld;
    
       bitfld.fields.f1 = id1;
       bitfld.fields.f2 = id2;
    
       dostuff(bitfld.value);
    

    在 dostuff 中,您可以通过以下方式轻松检索字段:

    
       void dostuff(unsigned long long bf) {
    
          union u_btfld a;
    
          a.value = bf;
    
          printf("id1 = %d\n", a.fields.f1);
          printf("id2 = %d\n", a.fields.f2);
    
       }
    

    【讨论】:

      【解决方案4】:

      假设 unsigned short 是 2 个字节,unsigned long 是 4 个字节。

      unsigned short id1 = 0x0d80; //3456 decimal
      unsigned short id2 = 0x7916; //30998 decimal
      unsigned long bitfld = ((id2<<16)|id1)  //id2<<16 = 0x79160000, so bitfld = 0x79160d80
      if ((bitfld & id1) == id1) {
          //id1 is in lower 2 bytes of bitfld
      }
      if ((bitfld>>16) &id2) == id2) { //bitfld>>16 = 0x00007916
          //id2 is in upper 2 bytes of bitfld
      }
      

      这有帮助吗? 在处理位时,如果使用十六进制值,则更容易直观地看到发生了什么。

      【讨论】:

      • 用值屏蔽 long 可能会产生不可预知的结果
      • alemjerus - 如果您担心 long 和 short 无符号整数的与运算,请将 short 转换为 long。
      • 有一些不错的运算符和定义可以在不假设每种类型的位的情况下使用:sizeof()CHAR_BITsizeof 运算符返回 chars 中的大小,CHAR_BIT 告诉每个 char 有多少位。乘以得到位数:bits = sizeof(int) * CHAR_BIT;
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多