C MACRO动态使用不同的定义

时间:2017-11-24 09:41:21

标签: c macros arm embedded

我尝试编写的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后缀。

2 个答案:

答案 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);
}