我正在阅读有关函数实现的代码,编写该代码的人将其写在他的.h中:
#define FT_LS_LONG (1 << 0)
#define FT_LS_RECURSIVE (1 << 1)
#define FT_LS_HIDDEN (1 << 2)
#define FT_LS_REVERSE (1 << 3)
#define FT_LS_TIME (1 << 4)
#define FT_LS_LINE (1 << 5)
为什么他使用按位左移而不是其他? 而且,他本可以用什么替换这部分代码? 我知道 (1 << 0)== 0000 0001 (1 << 1)== 0000 0010,依此类推。 但是我不知道如何使用它们。
答案 0 :(得分:3)
这些构造通常用于组合成单个单词的标志中。可以使用按位或运算符将它们合并,例如:
int flags = FT_LS_LONG | FT_LS_HIDDEN;
在上面的代码中,flags
变量将设置为0000 0101。
然后可以使用按位AND运算符来测试flags
变量,例如:
if (flags & FT_LS_LONG) { foo(); }
if语句的值为true,并且将调用foo()函数。
if (flags & FT_LS_TIME) { bar(); }
if语句的计算结果为false,并且不会调用bar()函数。
答案 1 :(得分:3)
它是自记录代码。 1
可能有任何含义,而1 << 0
绝对是位掩码。请注意,由于移位是整数常量表达式,因此在编译时对其进行求值。
更多的代码格式化将使其变得更加整洁:
#define FT_LS_LONG (1 << 0)
#define FT_LS_RECURSIVE (1 << 1)
#define FT_LS_HIDDEN (1 << 2)
#define FT_LS_REVERSE (1 << 3)
#define FT_LS_TIME (1 << 4)
#define FT_LS_LINE (1 << 5)
毫无疑问,这些是用于屏蔽来自同一字节的不同数据位的位屏蔽。
也可以使用十六进制文字编写等效代码,这只是样式问题:
#define FT_LS_LONG 0x01u
#define FT_LS_RECURSIVE 0x02u
#define FT_LS_HIDDEN 0x04u
#define FT_LS_REVERSE 0x08u
#define FT_LS_TIME 0x10u
#define FT_LS_LINE 0x20u
答案 2 :(得分:2)
他可能已经做到了,因为它更加清晰。 FT_LS_LONG
由第一(第零)位表示。他还可以将其保留为# define FT_LS_LONG 1
,但由于所有这些宏都包含在单个字节中,因此不清楚。
答案 3 :(得分:-1)
不看原始代码很难说,但这似乎是以可读的方式定义标志的。替代方法是使用#defines设置为0000001,0000010,0000100等。它的可读性较差且容易出错(如果错过0或1,将很难判断程序在哪里失败)
在实现中,我希望能看到按位排列,并且试图找出哪个标志是打开还是关闭。
答案 4 :(得分:-1)
正如其他答案所暗示的,这通常是由于使用标志引起的,但这不一定是唯一的原因。
例如,对于微控制器而言,地址空间非常宝贵,因此它们将多个属性打包在一个字节中,有时它们只是布尔标志,有时它们可能是其他东西,例如时钟分频因子,并且可能由几位组成,但是由于地址空间极为有限,因此它与其他标志和/或值存储在同一外围设备配置寄存器中,因此它们可能是例如从位2开始的5位,并且您可能会发现诸如0b10101 << 2
或以0x15 << 2
十六进制表示。
在微控制器的情况下,可以更轻松地在文档中查找,只需查看寄存器及其中的哪个位...因为您不必在二进制表示中计数0或将其转换为十六进制甚至更差的十进制来找出相应的值。