我很抱歉因为没有特权但我不知道它是怎么称呼的。这是我的问题:在this代码片段中,有一些常量定义如下:
#define WS_NONE 0
#define WS_RECURSIVE (1 << 0)
#define WS_DEFAULT WS_RECURSIVE
#define WS_FOLLOWLINK (1 << 1) /* follow symlinks */
#define WS_DOTFILES (1 << 2) /* per unix convention, .file is hidden */
#define WS_MATCHDIRS (1 << 3) /* if pattern is used on dir names too */
并且有一个如下定义的函数:
int walk_recur(char *dname, regex_t *reg, int spec)
他使用&#34; |&#34;发送常量(WS_DEFAULT和WS_MATCHDIRS):
walk_dir(".", ".\\.c$", WS_DEFAULT|WS_MATCHDIRS);
这就是他如何使用这些论点:
if ((spec & WS_RECURSIVE))
walk_recur(fn, reg, spec);
if (!(spec & WS_MATCHDIRS)) continue;
如果WS_RECURSIVE传递给function,则首先if语句为true。我没有得到&lt;&lt;&lt;&lt;运算符工作以及如何(spec&amp; WS_RECURSIVE)语句返回true。他怎么能用&#34; |&#34;?发送不同的常数?他可以使用&#34; spec&#34; value,必须等于传递的常量,这怎么可能?
抱歉我的英语不好。
答案 0 :(得分:4)
<<
运算符是按位左移。
例如,1 << 0
转换为1'左移'0位。这实际上是一个nop,因为1左移0位仍然是值1.
为了进一步说明,让我们看一个数字的按位表示(假设数字是一个16位值来说明)
1 - &gt; 0b'0000000000000001
1 << 1
将是
2 - &gt; 0b'0000000000000010
等等。
|
运算符是按位或,因此WS_DEFAULT | WS_MATCHDIRS
转换为:
0b'0001 | 0b'1000
这会产生值0b'1001
,然后传递给walk_dir。
如果您传入WS_RECURSIVE
,您将使用两个相同的值进行按位和(&
)操作。这将始终产生真正的价值。
AND 真值表
0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1
答案 1 :(得分:4)
将单个整数值视为单个位的集合是一种非常常见的习惯用法。 C不能直接支持位数组,因此我们使用按位运算符来设置和清除这些位。
<<
运算符是左移运算符。例如:
1 << 0 == 1
1 << 1 == 2
1 << 2 == 4
1 << 3 == 8
对于任何非负1 << n
(在范围内), n
是2的幂。整数值中的每个位表示2的幂。任何整数值都可以视为< em>唯一 2的幂和。
|
是按位或运算符;它用于将多个1位值(1的幂)组合成一个整数值:
(1 << 0) | (1 << 3) == 1 | 8
1 | 8 == 9
这里我们将位零(表示值1
)和位三(表示值8
)组合成单个值9
。 (在这种情况下,我们本可以使用+
而不是|
,但通常使用|
可以避免在多次使用2次幂时出现问题。)
现在我们可以使用按位和运算符&
测试是否设置了位:
int n = (1<<0) | (1<<3);
if (n & (1<<3)) {
printf("Bit 3 is set\n");
}
else {
printf("Bit 3 is not set\n");
}
现在我们可以定义宏,这样我们就不必在整个地方写1<<0
和1<<3
:
#define WS_RECURSIVE (1 << 0)
...
#define WS_MATCHDIRS (1 << 3)
int n = WS_RECURSIVE | WS_MATCHDIRS;
// n == 9
if (n & WS_RECURSIVE) {
// the WS_RECURSIVE bit is set
}
if (!(n&WS_MATCHDIRS) {
// the WS_MATCHDIRS bit is *not* set
}
您还可以定义宏来简化设置和测试位(SET_BIT()
,IS_SET()
等),但大多数C程序员都不愿意这样做。位值的符号名称对于代码可读性很重要,但是一旦理解了按位运算符的工作原理,更重要的是如何编写用于设置,清除和测试位的常用习惯用法,原始运算符就足够可读了。
使用无符号整数类型而不是有符号整数类型通常更好;在某些情况下,按位运算符在签名类型上的行为可能很棘手。