C - 检查一个变量是否是多个选项的*none*的最简洁的方法?

C - Most succinct way to check if a variable is *none* of many options?

背景:

通常,我们开发人员必须检查单个变量是否至少是多个选项中的一个。例如,

if ( (data == 125) || (data == 500) || (data == 750) )
{
    /* ... do stuff ...*/
}

建议 here(尽管是用 C# 编写的)提供了一个优雅的解决方案,可以像这样使用 switch 语句,

switch ( data )
{
    case 125:
    case 500:
    case 750:
        /* ... do stuff ...*/
        break;

    default:
        /* ... do nothing ... */
        break;
}

这适用于 "or" 条件,但对于否定的 "or" 条件就很丑陋,如下所示,

if ( !( (data == 125) || (data == 500) || (data == 750) ) )
{
    /* ... do stuff ...*/
}

可以写成

switch ( data )
{
    case 125:
    case 500:
    case 750:
        /* ... do nothing ... */
        break;

    default:
        /* ... do stuff ...*/
        break;

}

似乎有点老套。

问题:

是否有更简洁的方法来检查单个变量是否是多个选项的 none,例如上面否定的 "or" 条件?

参考文献:

我觉得后者还好

不过你可以更好地形式化它:

static bool in_sprawling_set(int data)
{
  switch ( data )
  {
    case 125:
    case 500:
    case 750:
        return true;
  }
  return false;
}

然后是您想在哪里做的工作:

if(!in_sprawling_set(data))
{
  /* do the work, not in set */
}

这将 "in set" 逻辑置于其自身的函数中,使其适度地自我记录,并且由于 ! 变得更加突出并且最终的 if 非常可读 ("if not in sprawling set").

注意:如果值的数量真的很大,我可能会使用预排序数组和二进制搜索,而不是巨大的 switch。我意识到一个足够聪明的编译器可以自己完成这个转换,但是一个巨大的 switch 的可读性会相当低(特别是如果你想每行只放一个 case )。有 bsearch() 用于搜索:

static int cmp_int(const void *ap, const void *bp)
{
  const int a = *(const int *) ap, b = *(const int *) bp;
  return a < b ? -1 : a > b;
}

static bool in_sprawling_set(int data)
{
  static const int values[] = { 125, 500, 750 };
  return bsearch(&data, values, sizeof values / sizeof *values, sizeof *values, cmp_int) != 0;
}

有很多样板代码,但您可以看到列出实际值的部分(唯一会随着添加更多值而增加的部分)更加紧凑。

Is there a more succinct way to check if a single variable is none of many options?

switch()语句当然是一个很好的解决方案。

作为替代方案,如果产品没有溢出,代码可以使用单分支测试:

unsigned data = foo();
if ( (data - 125) * (data - 500) * (data - 750) ) {
  /* ... do stuff as long as data is not 125, 500  or 750 ...*/
}

如果它更清楚 - 不是真的,它比 switch() 快吗? 它有潜力

您始终可以使用 De-morgans 定律来简化表达式,而不是否定条件

if (data != 125 && data != 500 && data != 750) ...