使用逻辑 ||带有枚举值
Posted
技术标签:
【中文标题】使用逻辑 ||带有枚举值【英文标题】:Using logical || with enum values 【发布时间】:2012-10-04 14:24:15 【问题描述】:我有一个 MPMoviePlayerController 实例。我希望检查它的playbackState 属性以获取多个值之一。因此,我会这样做:
if (moviePlayer.playbackState == (MPMoviePlaybackStateStopped ||
MPMoviePlaybackStatePlaying ||
MPMoviePlaybackStatePaused))
// ...
// Perform some logic
// ...
这按预期工作,但会导致编译器警告:
使用逻辑“||”使用常量操作数。
编译器的解决方法是改用按位|
运算符。在 Stack Overflow 上搜索你会发现 couple 的 answers 暗示了同样的事情。 但是使用按位 OR 真的不是我需要的。
MPMoviePlaybackState
在 MPMoviePlayerController.h 中声明:
enum
MPMoviePlaybackStateStopped,
MPMoviePlaybackStatePlaying,
MPMoviePlaybackStatePaused,
MPMoviePlaybackStateInterrupted,
MPMoviePlaybackStateSeekingForward,
MPMoviePlaybackStateSeekingBackward
;
typedef NSInteger MPMoviePlaybackState;
这不是位掩码(而且它也没有多大意义——枚举值是互斥模式,而不是要组合的标志)。我真的很想使用符合逻辑的||
。
(在我的特定情况下,基础值为 0,1,2,按位示例可能有效,但这只是巧合。)
我应该如何改写以避免警告或者我可以使用什么 #pragma clang diagnostic ignored ...
来消除警告?
(指向所有此类诊断列表的奖励积分 - 我似乎无法在手册中找到一个。)
提前致谢!
【问题讨论】:
【参考方案1】:显然,(enumval1 || enumval2 || ..)
是错误的。您不能像这样使用||
运算符,而只能使用逻辑表达式。|
运算符有效,因为它是一个简单的按位 OR,只有当您的枚举成员是 2 的不同幂(例如 1、2、4、8,...)时,它才会为您工作。
它与二进制数字的按位表示有关,如果数字是2的幂,则如下所示:2->10、4->100、8->1000等。所以,对于2 | 8
就像0010 | 1000 = 1010
,不是零,if
语句将继续。
编译器警告是完全正确的并且在这一点上有所帮助。使用switch(..)
或if(..) else if(..)
语句,或使您的枚举如下:
enum yourEnum
enumval1 = 1 << 0;
enumval2 = 1 << 1;
enumval3 = 1 << 2;
// ...
【讨论】:
我不知道这里的“明显”、“错误”或“不能”。语义上 (X||Y||Z) 正是我所追求的。这是正确的。我正在使用它。谢谢你的解释,但我确实理解按位表示。有问题的枚举是 Apple 的,所以很遗憾我无法更改它。 这与苹果无关。当您使用||
运算符时,操作数将转换为布尔类型。它变成真/假逻辑运算,而不是按位。
啊,是的——是选角。谢谢!你是对的,它与按位表示无关。 @wilsteel 的回答是最好的。
仍然不明白为什么他的答案是最好的。 :) 您对c++中逻辑运算符的基本点有一些误解,为什么提供一个使用switch语句的例子是最好的答案?..
"Best":只是它捕获了我的原始(错误)代码的意图——我想在枚举中交替可能的模式。鉴于底层表示,我不能用||
做到这一点——愚蠢的错误; IMO switch 是最清晰的选择——if
带有很多子句的语句(通常)更难阅读。【参考方案2】:
你为什么不这样做呢?
if ((moviePlayer.playbackState == MPMoviePlaybackStateStopped) ||
(moviePlayer.playbackState == MPMoviePlaybackStatePlaying) ||
(moviePlayer.playbackState == MPMoviePlaybackStatePaused))
// ...
// Perform some logic
// ...
【讨论】:
实际上,-O3
的代码可能是相同的...并且它将使用 x86 的 bsrq
指令来测试集合成员资格,而不是执行简单的 cmp
/je
, 在这两种情况下。就个人而言,我会使用if
处理一两个案例,switch
处理五个或更多案例,而 OP 的示例位于中间的灰色区域。【参考方案3】:
我建议使用带有跌谷逻辑的 switch/case 块:
switch(moviePlayer.playbackState)
case MPMoviePlaybackStateStopped: /* falls through */
case MPMoviePlaybackStatePlaying: /* falls through */
case MPMoviePlaybackStatePaused: /* falls through */
// your stuff
这将以尽可能少的代码实现预期的行为。枚举是为确切的开关案例类型的业务而制作的。并且它们比“if”语句更优化了性能,因为 CPU 在到达代码时甚至不必测试这些值。编译器在该位置计算正确的 ASM 跳转偏移量。所以它和闪电一样快:)
【讨论】:
投了反对票,因为您实际上没有解释 OP 的代码出了什么问题(||
的错位),以及关于性能的红鲱鱼(无论如何都是不正确的)。而对于“u”。
关于性能,我是对的。只是自己测试了一下以确保。这是代码:pastebin.com/7GNkpny5 关于||
:你没抓住重点。这不仅仅是“不明智”; OP 对||
的使用完全不正确。
呵呵,“那是因为你在使用优化。”欢迎来到二十世纪下半叶。 en.wikipedia.org/wiki/Switch_statement 对我来说看起来不错,尽管“历史”部分的符号有点重。常见的优化在标题为“优化开关”的部分中讨论。以上是关于使用逻辑 ||带有枚举值的主要内容,如果未能解决你的问题,请参考以下文章