计算访问位域的哪个元素的宏

Macro to compute which element of a bit field is accessed

我想创建一个宏来从如下结构中轻松访问单个位:

typedef union 
{
    struct 
    {
        uint8_t bit0 : 1;
        uint8_t bit1 : 1;
        uint8_t bit2 : 1;
        uint8_t bit3 : 1;
        uint8_t bit4 : 1;
        uint8_t bit5 : 1;
        uint8_t bit6 : 1;
        uint8_t bit7 : 1;
    };
    uint8_t raw;
} Bitfield;

我有一个这种结构的二维数组(x)。我能做的最好的是:

#define xstr(r,c,b) str(r,c,b)
#define str(r,c,b) (x[r][c].bit##b)
#define getBit(bitCollum,row)(xstr(row,(bitCollum/8),(bitCollum%8))

当我尝试使用像 uint8_t a = getBit(15,2); 这样的宏时,它会扩展为

 uint8_t a = ( ( img [ 2 ] [ ( 15 / 8 ) ] . bit 15 % 8 ) );

我想创建一个可以扩展到的结构:

 uint8_t a = ( ( img [ 2 ] [ ( 15 / 8 ) ] . bit7 ) );

这可能吗?

bitCollumrow 将始终是字面整数;表达式不会 运行 在循环或类似的东西中。

编辑:

在看到这是不可能的之后,我查看了一个简单增量的反汇编,我看到了不同的指令,但令我惊讶的是,屏蔽速度更快。

` x.raw = 0b10101001;
00000040  LDI R24,0xA9      Load immediate 
00000041  STD Y+8,R24       Store indirect with displacement 
   uint8_t y = 0b10101001;
00000042  LDI R24,0xA9      Load immediate 
00000043  STD Y+1,R24       Store indirect with displacement 
   uint16_t xSum=0;
00000044  STD Y+3,R1        Store indirect with displacement 
00000045  STD Y+2,R1        Store indirect with displacement 
   uint16_t ySum=0;
00000046  STD Y+5,R1        Store indirect with displacement 
00000047  STD Y+4,R1        Store indirect with displacement 
   xSum+=x.bit3;
00000048  LDD R24,Y+8       Load indirect with displacement 
00000049  BST R24,3     Bit store from register to T 
0000004A  CLR R24       Clear Register 
0000004B  BLD R24,0     Bit load from T to register 
0000004C  MOV R24,R24       Copy register 
0000004D  LDI R25,0x00      Load immediate 
0000004E  LDD R18,Y+2       Load indirect with displacement 
0000004F  LDD R19,Y+3       Load indirect with displacement 
00000050  ADD R24,R18       Add without carry 
00000051  ADC R25,R19       Add with carry 
00000052  STD Y+3,R25       Store indirect with displacement 
00000053  STD Y+2,R24       Store indirect with displacement 
   ySum+=y&0b00010000;
00000054  LDD R24,Y+1       Load indirect with displacement 
00000055  MOV R24,R24       Copy register 
00000056  LDI R25,0x00      Load immediate 
00000057  ANDI R24,0x10     Logical AND with immediate 
00000058  CLR R25       Clear Register 
00000059  LDD R18,Y+4       Load indirect with displacement 
0000005A  LDD R19,Y+5       Load indirect with displacement 
0000005B  ADD R24,R18       Add without carry 
0000005C  ADC R25,R19       Add with carry 
0000005D  STD Y+5,R25       Store indirect with displacement 
0000005E  STD Y+4,R24       Store indirect with displacement `
#define GET_BIT(VAR8,IDX)   ((VAR8>>IDX) & 1)


int main(void){
    unsigned char c=3;
    int i;
    printf("Bits of char %d: ",c);
    for(i=0; i<8;i++){
        printf("%d ",GET_BIT(c,i));
    }
    printf("\n");
    return 0;
}

使用简单的字节而不是结构 - uint8_t

#define GETBIT(r,c) (img[r][(c) >> 3] & (1 << ((c) & 7)))
#define SETBIT(r,c) img[r][(c) >> 3] |= (1 << ((c) & 7))
#define CLRBIT(r,c) img[r][(c) >> 3] &= ~(1 << ((c) & 7))

但是,如果您希望它高效,最好避免一次一位地进行操作。

可能是我遗漏了一些 "trick",但是,据我所知,这是不可能的。

基本上,您正在尝试计算一个值,然后将其附加到某个标记。这里的问题是预处理器不进行计算(#if 和此类语句除外)。所以,例如:

#define X2(A,B) A##B
#define X(A,B) X2(A,B)

int x = X(13 + 4, 4);

这将扩展为:

int x = 13 + 44;

到:

int x = 174;

如果您尝试放入括号,您只会得到编译器错误,因为这是无效的:

int x = (13+4)4;

在处理宏时,一切都只是预处理器的 "string"(标记)。实际上,在上面的示例中,编译器会看到 13 + 44 是常量并将其编译为 int x = 57;(好吧,一个智能编译器,我以前使用过一些 C 编译器,它们是不太聪明 :)).