C - 函数参数和"<<"操作者

时间:2014-07-22 21:54:38

标签: c function operators constants

我很抱歉因为没有特权但我不知道它是怎么称呼的。这是我的问题:在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,必须等于传递的常量,这怎么可能?

抱歉我的英语不好。

2 个答案:

答案 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<<01<<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程序员都不愿意这样做。位值的符号名称对于代码可读性很重要,但是一旦理解了按位运算符的工作原理,更重要的是如何编写用于设置,清除和测试位的常用习惯用法,原始运算符就足够可读了。

使用无符号整数类型而不是有符号整数类型通常更好;在某些情况下,按位运算符在签名类型上的行为可能很棘手。