【问题标题】:Set and Reset of Bitfields位域的设置和重置
【发布时间】:2017-05-17 20:05:32
【问题描述】:

我正在尝试编写一个 C 程序,其中我将声明两个类型为 status 位域的变量,状态 a 和状态掩码。而在 status a 中我只能设置掩码中已经设置的位域。

#include<stdio.h>

typedef struct
{
    unsigned int w : 1 ;
    unsigned int x : 1 ;
    unsigned int y : 1 ;
    unsigned int z : 1 ;
}status ;

void bitset(status* a,status* b,int position)
{
    /*Check for the position and set that bit only if it is set in mask.
     In this case, I can set only a.x and a.z.

}
int main()
{
    status a ;
    status mask ;
    int position ;

    mask.w = 0
    mask.x = 1 ;
    mask.y = 0;
    mask.z = 1;

    position = 1 ;

    bitset(&a,&b,position); 
}

为此,我尝试使用 & 运算符。但它显示错误。

Q1:通过使用指向 ama​​sk 的指针如何完成函数 bitset。

Q2:有没有办法让我一次设置所有位域,比如 a = 0x10,因此只设置了 y 位。

Q3:有没有办法让我一次重置所有位,例如 a={0}。这是正确的做法吗?请帮忙。

【问题讨论】:

  • Q1去哪儿了?
  • 请修复 cmets。您打开了评论但忘记关闭它。并添加能说明问题的代码
  • int position ; 未初始化,mask.wmask.y 也是如此。
  • 如果您使用这样的位域,您几乎可以将w,x,y,z 全部视为单独​​的变量,并为它们分配值。如果您想一次设置或清除多个值,那么您可能想放弃位域语法并开始使用&amp;| 一次设置整个位范围。
  • 我已经更新了问题

标签: c bits bit-fields


【解决方案1】:

A2:不是便携式的;您可以将其放入带有整数成员的union 中,并对位域进行洗牌,使其适用于您的 ABI。但如前所述,这不是便携式的

A3:memset(&amp;a, 0, sizeof a) 应该这样做

但是:位域很丑陋,对于您的用例来说可能是错误的选择。我会使用无符号整数。

【讨论】:

    【解决方案2】:

    A1:如果你想设置一个位,你应该使用 OR 运算符,而不是 AND。通过指针访问位类似于通过变量访问位。唯一的区别在于“->”而不是“.”。 IE。 a->w 而不是 a.w;

    A2:是的,有。例如,声明一个指向同一内存位置的整数指针,并使用它作为整数变量访问内存。请参阅下面的示例代码。缺点是您可以访问结构占用的所有位。

    A3:与 A2 相同。可以设置,也可以重置。

    #include <stdio.h>
    
    typedef struct {
      int a:1;
      int b:1;
      int c:1;
      int d:1;
    } bitField;
    
    int main() {
      bitField A;
      bitField B;
    
      int *allA;
      allA = (int *)&A;     //Access bitField as Integer
    
      *allA = 0x02;         //Set bit 2 of A
      printf("A=0x%x\n", A);
    
      *allA = 0x53;         //Set bits 1 and 2 of A, but also set a few of "out of range" bits
      printf("A=0x%x\n", A);
    
      *allA = 0x01;         //Set bit 1, reset all other bits
      printf("A=0x%x\n", A);
    
      B.c = 1;              //Set Bit 3 of B
    
      A.c |= B.c;           //A=0b0001, B=0b0100 -> A|B=0b0101 (dec 5)
      printf("A=0x%x\n", A);
    
      int *allB;
      allB = (int *)&B;
    
      *allA = 0;
      *allB = 3;
      *allA |= *allB;       //Set bits 1 and 2 of A by OR-ing with B;
      printf("A=0x%x\n", A);
    }
    

    【讨论】:

    • 对同一个变量使用位域操作和整型位操作是不可移植的。例如,在 bigendian 机器上,B.c 可能不是位 3,而是位 sizeof(int) * 8 - 3。
    • 嗨 Sokre,我不能使用 OR 运算符来设置位,因为条件是我只能设置在你的情况下掩码位域中已经设置的位,比如位域 b。所以如果 B = 0b0100我想设置位域 a 的第一位,即 0b0001 ,我不应该这样做。根据条件,我只能设置和重置 a 的第 3 位。(B = 0b0100)。这就是为什么我想使用 AND 运算符
    • 嗨,那么您应该将 MASK 与 B 和 OR 结果与 A。AND-ing 将只保留 B 和掩码中的位,OR-ing 将设置 A 中的结果位. 当然,假设 A 在这一切之前被重置。
    • @Doug Currie - 你可能是对的,但我对此表示怀疑。为了这个讨论,我不明白为什么在寄存器上执行 OR-ing/AND-ing 时如何将“按位拆分”整数存储在内存中很重要。定义的结构具有整数作为基础类型。当整数从内存加载到寄存器中时,它将被“正确排序”。还是?
    • @Skore,不,处理器在读取/写入内存时不会端到端翻转位。不幸的是,C 没有指定 int 中位域的布局;你不能依赖它。见securecoding.cert.org/confluence/display/c/…stackoverflow.com/questions/6043483/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-08
    • 2010-11-20
    相关资源
    最近更新 更多