【问题标题】:What is the meaning of this declaration? [closed]这个声明的含义是什么? [关闭]
【发布时间】:2013-03-20 11:08:42
【问题描述】:

我不是 C/C++ 方面的专家。

我今天找到了这个声明:

typedef NS_OPTIONS(NSUInteger, PKRevealControllerType)
{
    PKRevealControllerTypeNone  = 0,
    PKRevealControllerTypeLeft  = 1 << 0,
    PKRevealControllerTypeRight = 1 << 1,
    PKRevealControllerTypeBoth = (PKRevealControllerTypeLeft | PKRevealControllerTypeRight)
};

你们能翻译一下每个值都有什么值吗?

【问题讨论】:

  • 看起来像 Objective C,而不是 C++
  • 哪种语言?没有像 C/C++ 这样的语言,这看起来仍然是一种不同的语言。那那个宏呢? NS_OPTIONS 是什么?
  • 算了。我想知道其他三个值中的每一个都有什么值。 1
  • @David: NS_OPTIONS 是一个 Objective-C 特定的宏;见this question。但显然这不是 OP 所要求的。
  • 阅读文档有什么问题

标签: ios objective-c c cocoa-touch cocoa


【解决方案1】:

opertor &lt;&lt;按位 左移运算符。将所有位左移指定次数:(算术左移并保留符号位)

m << n

m 的所有位向左移动n 次数。 (注意一次移位 == 乘以二)。

1 &lt;&lt; 0 表示 no 移位,因此它仅等于 1

1 &lt;&lt; 1 表示 one 移位,因此它仅等于 1*2 = 2。

我用一个字节解释:一个字节是这样的:

 MSB
+----+----+----+---+---+---+---+---+
|  0 |  0 | 0  | 0 | 0 | 0 | 0 | 1 |       1   
+----+----+----+---+---+---+---+---+
  7     6   5    4   3   2   1 / 0  
  |                           /           1 << 1
  |                          | 
  ▼                          ▼
+----+----+----+---+---+---+---+---+
|  0 |  0 | 0  | 0 | 0 | 0 | 1 | 0 |       2      
+----+----+----+---+---+---+---+---+ 
   7    6   5    4   3   2   1   0

1 &lt;&lt; 0 只做图一。 (注意第 7 位被复制以保留符号)

OR 运算符:按位或

 MSB                            PKRevealControllerTypeLeft
+----+----+----+---+---+---+---+---+
|  0 |  0 | 0  | 0 | 0 | 0 | 0 | 1 |  == 1
+----+----+----+---+---+---+---+---+
   7    6   5    4   3   2   1   0
   |    |    |   |   |   |   |   |      OR
 MSB                               PKRevealControllerTypeRight
+----+----+----+---+---+---+---+---+
|  0 |  0 | 0  | 0 | 0 | 0 | 1 | 0 |   == 2
+----+----+----+---+---+---+---+---+
   7    6   5    4   3   2   1   0

 = 

 MSB                    PKRevealControllerTypeBoth
+----+----+----+---+---+---+---+---+
|  0 |  0 | 0  | 0 | 0 | 0 | 1 | 1 |   == 3
+----+----+----+---+---+---+---+---+
   7    6   5    4   3   2   1   0  

| 是位操作符。在下面的代码中 or 1 | 2 == 3

PKRevealControllerTypeNone  = 0,             //  is Zero
PKRevealControllerTypeLeft  = 1 << 0,        //  one 
PKRevealControllerTypeRight = 1 << 1,        //  two
PKRevealControllerTypeBoth = (PKRevealControllerTypeLeft |    
                             PKRevealControllerTypeRight)  // three

没有更多的技术原因来初始化像这样的值,像这样定义会让事情很好地排列起来阅读这个答案:define SOMETHING (1 << 0)

编译器优化将它们转换成更简单的形式:(我不确定第三个,但我认为编译器也会优化它

PKRevealControllerTypeNone  = 0,     //  is Zero
PKRevealControllerTypeLeft  = 1,     //  one 
PKRevealControllerTypeRight = 2,     //  two
PKRevealControllerTypeBoth  = 3,     // Three

编辑: @thanks to Till。 阅读此答案App States with BOOL flags 显示使用位运算符获得的声明的有用性。

【讨论】:

  • 将它设置为 0、1、2、3 不是更容易吗?有什么理由这么疯狂吗?
  • 明确表示是一组位标志
  • @DesperateDeveloper 我不认为我相信程序员这样做是为了让他的这部分代码与其他部分代码一致
  • +1 ASCII 艺术的胜利!
  • @DesperateDeveloper 想要很好地解释为什么人们会使用如此复杂的表达方式,您可能需要检查问题/答案,例如 stackoverflow.com/a/8956606/91282
【解决方案2】:

这是一个位标志的枚举:

PKRevealControllerTypeNone  = 0       // no flags set
PKRevealControllerTypeLeft  = 1 << 0, // bit 0 set
PKRevealControllerTypeRight = 1 << 1, // bit 1 set

然后

PKRevealControllerTypeBoth = 
  (PKRevealControllerTypeLeft | PKRevealControllerTypeRight)

只是对其他两个标志进行按位或运算的结果。所以,位 0 和位 1 设置。

&lt;&lt; 运算符是左移运算符。而| 运算符是按位或。

总而言之,结果值为:

PKRevealControllerTypeNone  = 0
PKRevealControllerTypeLeft  = 1
PKRevealControllerTypeRight = 2
PKRevealControllerTypeBoth  = 3

但是从位标志的角度来考虑它会更有意义。或者作为通用集的集合:{ PKRevealControllerTypeLeft, PKRevealControllerTypeRight }

要了解更多信息,您需要阅读枚举、移位运算符和位运算符。

【讨论】:

    【解决方案3】:

    这看起来像 Objective C 而不是 C++,但无论如何:

    1 << 0
    

    只是向左(上)0 个位置移动一位。任何整数“

    所以

    1 << 0 = 1
    

    同样

    1 << 1
    

    只是左移一位。您可以通过多种方式对其进行可视化,但最简单的方法是乘以 2。[注 1]

    所以

    x << 1 == x*2
    

    1 << 1 == 2
    

    最后,单管道运算符是bitwise or

    所以

    1 | 2 = 3
    

    tl;博士:

    PKRevealControllerTypeNone  = 0
    PKRevealControllerTypeLeft  = 1
    PKRevealControllerTypeRight = 2
    PKRevealControllerTypeBoth  = 3
    

    [1] 这种泛化存在一些限制,例如当x 等于或大于该数据类型能够存储的最大值的 1/2 时。

    【讨论】:

    • 将它设置为 0、1、2、3 不是更容易吗?有什么理由这么疯狂吗?
    • @DesperateDeveloper 这些值是标志而不是数字。这种设置很明显每个标志都是独立的,最后一个是其他两个的组合。如果您有 20 个标志,“正常”数字将难以管理; 65544有什么作用?在这种形式下,我会知道它是(1&lt;&lt;16) | (1&lt;&lt;3),这意味着它代表 2 个标志。只需学习位移运算符,它就不再“疯狂”了。
    • 嗯,它编译成相同的代码,所以唯一的区别是它在源代码中的表达方式。我认为这种方法可能比 0,1,2,3 更好。三件事让它看起来很奇怪,[1] 他们为“无”(0)定义了一个单独的值。这不是经常做的。 [2] 他们为 (1|2) 定义了一个单独的变量。通常也不会这样做。通常标志的十进制值以 2 的幂增加 - 1、2、4、8、16 等。并且[3],位域中只使用了2位。通常还有更多。
    • @jedwards 我总是定义一个 0 值,因为(在 C++ 中)如果您在不需要标志时只发送 (int) 0 会不开心,而且您不能总是依赖默认值.组合标志也很常见,就像别名一样,因为它使使用该函数的代码更具可读性。拥有如此短的位域也不是那么不寻常!事实上,标准 cocoa 库有很多(几乎)这么短的示例。
    • @Dave,感谢您的洞察力。我自己不是 ObjC 开发人员,所以关于可可库的注释很有趣。如果我别名,我通常会在一个单独的地方做,但我猜他们是在这里做的——长度是误导性的。至于定义 0,这很有意义——我的 C 背景比我强 :-)
    【解决方案4】:

    这一切都归结为按位算术。

    PKRevealControllerTypeNone 的值为 0(二进制 0000)

    PKRevealControllerTypeLeft 的值为 1(二进制 0001)

    PKRevealControllerTypeRight 的值为 2(二进制 0010),因为 0001 左移 1 位是 0010

    PKRevealControllerTypeBoth 自 0010 以来的值为 3(二进制 0011)| 0001(或类似加法)= 0011

    在上下文中,这最有可能用于确定值。属性为&amp;(或bitwise-and)的工作方式类似于乘法。如果1 与数字并存,则保留该数字,如果0 与数字并存,则该数字被清除。

    因此,如果您想检查特定控制器是否是特定类型 Left 并且它的值是 0010(即类型 Right0010 &amp; 0001 = 0,正如我们所期望的那样(因此,您有确定它的类型不正确)。但是,如果控制器是 Both 0011 &amp; 0001 = 1,那么结果是正确的,因为我们确定这是 Both 类型。

    【讨论】:

    • 0000, 0001, 0010, 0011... ?将其设置为 0、1、2、3 不是更容易吗?有什么理由这么疯狂吗?
    • 我在回复中添加了更多内容 - 您可以查看实际使用情况。
    • @DesperateDeveloper:看到像“2”这样的数字并不能轻易告诉您该数字中设置了哪些位。左移表达式可以。如果您打印PKRevealControllerType 变量的值并想知道其中设置了哪些选项,这将变得很重要;您可以将数字粘贴到计算器中,切换到程序员模式,然后查看位显示。
    猜你喜欢
    • 1970-01-01
    • 2022-11-01
    • 1970-01-01
    • 2019-12-14
    • 2013-01-23
    • 1970-01-01
    • 2014-09-20
    相关资源
    最近更新 更多