Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用C语言和assemby语言一样优雅地设置标志_C_C Preprocessor_Flags - Fatal编程技术网

用C语言和assemby语言一样优雅地设置标志

用C语言和assemby语言一样优雅地设置标志,c,c-preprocessor,flags,C,C Preprocessor,Flags,与汇编语言相比,C语言中的标记处理感觉很麻烦 我正在寻找一种使C代码像汇编代码一样可读的方法 在汇编中: #define powerOn flagsByte,0 ... bsf powerOn ; Turn on the power bcf powerOn ; Turn off the power btfsc powerOn ; If the power is on... #define bsf(X) flagsByte.(X) = 1 #define bcf(X) flagsByte.(X

与汇编语言相比,C语言中的标记处理感觉很麻烦

我正在寻找一种使C代码像汇编代码一样可读的方法

在汇编中:

#define powerOn flagsByte,0
... 
bsf powerOn ; Turn on the power
bcf powerOn ; Turn off the power
btfsc powerOn ; If the power is on...
#define bsf(X) flagsByte.(X) = 1
#define bcf(X) flagsByte.(X) = 0
在C中:

但这不起作用,因为它扩展到:

flagsByte,0 |= (1<<())

您可以
#定义powerOn flagsByte |=(1使用GCC,您可以定义所谓的位字段,并像处理结构成员一样操作它们:

struct flagsByte
  {
    unsigned int powerOn: 1;  /* single bit */
  };

flagsByte.powerOn = 0;
flagsByte.powerOn = 1;
在此基础上,可以定义两个简单的宏,让人想起汇编:

#define powerOn flagsByte,0
... 
bsf powerOn ; Turn on the power
bcf powerOn ; Turn off the power
btfsc powerOn ; If the power is on...
#define bsf(X) flagsByte.(X) = 1
#define bcf(X) flagsByte.(X) = 0
然后简单地写

bsf(powerOn);  /* set flag   */
bcf(powerOn);  /* clear flag */

不幸的是,这并不适用于每一个C编译器。

这里有一组与您的汇编示例非常匹配的宏:

#define powerOn        0
#define someotherfield 1

#define BITMASK(field) (1u << (field))
#define SET(field)  do { flagsByte |= BITMASK(field); } while(0)
#define CLR(field)  do { flagsByte &= ~BITMASK(field); } while(0)
#define TEST(field) (flagsByte & BITMASK(field))

/* Use examples */
SET(powerOn);
CLEAR(powerOn);
if (TEST(powerOn)) {
    // Danger!
}
#定义开机0
#定义其他字段1

#定义位掩码(字段)(1u您可以只定义一些常量,而不使用预处理器,而是使用枚举来减少意外:

enum flags{
    powerOn = 1<<0,
    powerMask = ~powerOn,
    /*...*/
};
在C(和C++)中有一个很好的经验法则:如果可以避免,请不要使用预处理器


无论如何,如果您能够接受位字段固有的实现定义,请按照Roberto Reale的建议使用位字段。

您可以通过第二次扩展来实现这一点

~/sandbox/20$ cat >t.c
#define BITSET_INNER(a,b) a |= (1<<b)
#define BITSET(spec) BITSET_INNER(spec)
#define f1 flagword,3

    BITSET(f1)

~/sandbox/20$ cc -E t.c
# 1 "t.c"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "t.c"




    flagword |= (1<<3)
~/sandbox/20$cat>t.c

#定义位集_INNER(a,b)a |=(1就我个人而言,我更喜欢位域语法,并且不使用宏,因为我的标志几乎总是在结构内部。但是,如果你坚持用C编写汇编程序,下面是方法:

/* We need to indirect the macro call so that the pair of arguments get expanded */
#define BITSET_(f,i) do{f|= 1<<(i);}while(0)
#define BITCLR_(f,i) do{f&=~(1<<(i));}while(0)
#define BITCHK_(f,i) ((f)&(1<<(i)))

#define BITSET(fi) BITSET_(fi)
#define BITCLR(fi) BITCLR_(fi)
#define BITCHK(fi) BITCHK_(fi)

/* Define the flag container and bit number as per OP */
#define poweron flags1,0
#define warnuser flags7,4

/* Sample uses */
BITSET(poweron);
BITCLR(warnuser);
/* Since BITCHK expands to a parenthesized expression, I can get away with
 * leaving out the parentheses in the if statement. Not saying that's a good
 * idea or anything.
 */
if BITCHK(poweron) BITSET(warnuser);
/*我们需要间接调用宏,以便展开这对参数*/

#define BITSET_f(f,i)do{f|=1有趣。谢谢。但是我有几十个标志,我真的无法想象写几十个宏,三个宏(一个用来设置,一个用来清除,一个用来测试)对于每个标志。啊,我不知道。ArtemB似乎有一个优雅的解决方案可以解决这个问题。谢谢。它并没有完全回答我的问题,假设#定义powerOn flagsByte,0。在你的解决方案中,“flagsByte.powerOn”确实包含“flagsByte”一词,它没有汇编那么优雅。不过,非常好,谢谢。位字段不是gcc扩展。它们是标准C的一部分,因此在任何符合规范的编译器上都应该可用。“#定义bsf(X)flagsByte.(X)=1”这意味着我需要一个单独的宏来处理每个变量的位。这包括各种特殊的函数寄存器,以及各种字节的标志。我不希望这样。“struct flagsByte”将适用于标记字节,我将根据需要对其进行定义。但不适用于特殊功能寄存器,该寄存器已由项目中包含的处理器文件定义。如果您希望在多个寄存器中设置多个位(如您在对ArtemB答案的评论中所述),您将不可避免地必须同时引用寄存器/变量和要设置的位。按照您的方法,我需要为每个要操作其位的变量使用3个单独的宏。这包括各种特殊函数寄存器,以及各种字节的标志。这将是几十个宏。我不会期待我很喜欢你的“位掩码(字段)”(1u我已经用允许在字段定义中使用变量名的宏的变体更新了我的答案。但是,IMHO,这几乎是预处理器滥用。我检查了您的更新,是的,它现在完全回答了我的问题;谢谢。我看到您使用的解决方案与jthill和rici提供的相同:2个宏扩展。我不确定为“优雅”设置目标变量或寄存器当有数百个寄存器被CPU和外设所暴露时,例如,考虑一个代码>重置< /代码>位。是WiFi芯片的<代码>重置< /代码>?AES加密引擎?TX数据路径?RX数据路径?DCM时钟?串行端口?看门狗?CPU等等。我相信CLR(SerrxIntFLG)。(用一个#define serxinterflg PIF1,U1RxIF,其他地方)比PIF1可读性好得多&=!(哇!谢谢!你的方法似乎和rici的方法一样,对吧?De nada,hf,感谢atcha:-)提振了我的情绪。(编辑:是的。)太好了!那就可以了。你的方法似乎和jthill的方法一样,对吧?也就是说,诀窍是做两次宏展开。@DavideAndrea:显然是这样。我没有看到他的答案。嗯,@rici,你的先到,所以我把它标记为可接受的解决方案。我发现你的解决方案比标准的C解决方案更优雅,尽管可能是Be没有大会那么优雅。我真的很感谢你。
#define powerOn        0
#define someotherfield 1

#define BITMASK(field) (1u << (field))
#define SET(field)  do { flagsByte |= BITMASK(field); } while(0)
#define CLR(field)  do { flagsByte &= ~BITMASK(field); } while(0)
#define TEST(field) (flagsByte & BITMASK(field))

/* Use examples */
SET(powerOn);
CLEAR(powerOn);
if (TEST(powerOn)) {
    // Danger!
}
#define powerOn        flagsByte,0                                                                                                                                                      
#define someotherfield flagsByte,1                                                                                                                                                      

#define BITMASK(field) (1u << (field))                                                                                                                                                  
#define _SET(var, field)  do { var |= BITMASK(field); } while(0)                                                                                                                        
#define SET(x) _SET(x)

/* Use examples */                                                                                                                                                                      
SET(powerOn);
enum flags{
    powerOn = 1<<0,
    powerMask = ~powerOn,
    /*...*/
};
flagsByte |= power;
flagsByte &= ~power;
flagsByte &= powerMask; /* same as previous line */
~/sandbox/20$ cat >t.c
#define BITSET_INNER(a,b) a |= (1<<b)
#define BITSET(spec) BITSET_INNER(spec)
#define f1 flagword,3

    BITSET(f1)

~/sandbox/20$ cc -E t.c
# 1 "t.c"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "t.c"




    flagword |= (1<<3)
/* We need to indirect the macro call so that the pair of arguments get expanded */
#define BITSET_(f,i) do{f|= 1<<(i);}while(0)
#define BITCLR_(f,i) do{f&=~(1<<(i));}while(0)
#define BITCHK_(f,i) ((f)&(1<<(i)))

#define BITSET(fi) BITSET_(fi)
#define BITCLR(fi) BITCLR_(fi)
#define BITCHK(fi) BITCHK_(fi)

/* Define the flag container and bit number as per OP */
#define poweron flags1,0
#define warnuser flags7,4

/* Sample uses */
BITSET(poweron);
BITCLR(warnuser);
/* Since BITCHK expands to a parenthesized expression, I can get away with
 * leaving out the parentheses in the if statement. Not saying that's a good
 * idea or anything.
 */
if BITCHK(poweron) BITSET(warnuser);