我尝试编写的MACRO的目的是更新传递由Value,position和length定义的新值的char。让我举个例子来更好地解释一下:
原始值:0b11000011 要更新的值:0b11 放置位置:4 长度到新值:2
基本上我想在字节的中间放置两位(0b11)(0b110 00 011)以便有一个新字节(0b110 11 011)
我现在拥有的MACRO就像是
#define UPDATE_REG(REG, MASK, POS, LEN, VAL) ((REG) = (((REG) & (MASK)) | (VAL<<(POS +1 -LEN))))
它运作良好。例如,在我的标题中,我有像
这样的定义#define CP_BYP_MODE_SAD 0x38
#define CP_BYP_MODE_ADR 0xD4
#define CP_BYP_MODE_POS 4
#define CP_BYP_MODE_LEN 3
#define CP_BYP_MODE_DEF 0b00
#define CP_BYP_MODE_MSK 0b11100111
并使用MACRO我写下面的代码
uint8_t Reg = 0b11000011;
UPDATE_REG(Reg, CP_BYP_MODE_MSK, CP_BYP_MODE_POS, CP_BYP_MODE_LEN, 0b11);
这个解决方案效果很好,但我的观点是我想用一些技巧来减少参数(如果可能的话),考虑到我会在每个调用中使用三个由以下内容组成的定义: name_MSK name_POS name_LEN
为了清楚起见,我的目标是拥有类似
的MACRO#define UPDATE_REG(REG, NAME, VAL) ((REG) = (((REG) & (**NAME_MSK**)) | (VAL<<(**NAME_POS** +1 - **NAME_LEN**))))
例如,能够获得CP_BYP_MODE_POS仅传递CP_BYP_MODE并能够自动添加_POS后缀。
答案 0 :(得分:1)
首先,真的没有必要为此编写模糊的宏,你只会让代码更难阅读。不幸的是,人们试图在抽象层后面隐藏简单的逐位算术,这只是因为它们发现了逐位算术技巧。
你应该做的是保持简单:
uint8_t reg = 0xC3;
uint8_t mask = 0x18;
uint8_t new_val = 0x18;
reg &= ~mask; // clear values with mask
reg |= new_val; // write new value to the cleared position
值得注意的是,如果你知道面具,那就意味着你已经知道了尺寸和位置。您可以根据尺寸和位置计算遮罩,如下所示:
mask = ((1 << size)-1) << pos;
size = 2,pos = 3给出:
1 << 2
= 0000 0100b = 0x04
0x04-1
= 0000 0011b = 0x03
0x03 << 3
= 0001 1000b = 0x18
答案 1 :(得分:0)
也许这就是你想要的:
/* this bitfield may appear in more places: */
#define TWO_BITS_FOR_ALICE 4,2 /*starting bit, length in bits*/
#define REG1_TWO_BITS_FOR_ALICE REG1,TWO_BITS_FOR_ALICE
/* this is a global bitfield, e.g. some unique hardware register: */
#define REG1_TWO_BITS_FOR_BOB REG1,0,2 /*destination,starting bit,length in bits */
#define MASK_OUT(start,length) ~(MASK_IN((start),(length)))
#define MASK_IN(start,length) ((-1u<<(start))+(1u<<((start)+(length))))
#define SET_GBFLD(bfld,value) _SET_BFLD(bfld,value)
#define SET_BFLD(target,bfld,value) _SET_BFLD(target,bfld,value)
#define _SET_BFLD(target,start,length,value) ((target) = ((target)&MASK_OUT((start),(length))) | (((value) & MASK_IN(0,(length)))<<(start)))
#include <stdio.h>
int main(void)
{
unsigned REG1 = 0;
SET_GBFLD(REG1_TWO_BITS_FOR_ALICE,7);
SET_GBFLD(REG1_TWO_BITS_FOR_BOB,7);
printf("%04x ",REG1);
unsigned REG2 = 0;
SET_BFLD(REG2,TWO_BITS_FOR_ALICE,7);
printf("%04x ",REG2);
}