【问题标题】:How to make conditional statements more compact in C?如何在 C 中使条件语句更紧凑?
【发布时间】:2021-12-11 17:42:02
【问题描述】:

我有一个使用 if-else if-else 块的代码 sn-p。例如,我想知道在不改变逻辑的情况下缩短冗长的条件语句else if (cardLength == 16) && (numberArray[0] == 5 && (numberArray[1] == 1 || numberArray[1] == 2 || numberArray[1] == 3 || numberArray[1] == 4 || numberArray[1] == 5)) 的任何潜在方法。在python中,我可以这样做:if (cardLength == 16) and (numberArray[0:2] in range(51,56))。我可以在 C 中为此目的使用任何特定的语法糖吗?

if (cardLength == 15) &&
   (numberArray[0] == 3 && (numberArray[1] == 4 || numberArray[1] == 7))
{
    printf("AMEX\n");
}
else if (cardLength == 16) &&
        (numberArray[0] == 5 && (numberArray[1] == 1 || numberArray[1] == 2 || numberArray[1] == 3 || numberArray[1] == 4 || numberArray[1] == 5))
{
    printf("MASTERCARD\n");
}
else if (cardLength == 13) && (numberArray[0] == 4)
{
    printf("VISA\n");
}
else
{
    printf("INVALID\n");
}

【问题讨论】:

  • 而不是numberArray[1] == 1 || numberArray[1] == 2 || numberArray[1] == 3 || numberArray[1] == 4 || numberArray[1] == 5 或者numberArray[1] >= 1 && numberArray[1] <= 5
  • 另一方面,拥有更“紧凑”的代码并不总是可取的,因为这通常会使代码更难阅读、理解和维护。编译器也很聪明,所以通常更“紧凑”的代码并不一定意味着在编译器优化后代码更有效。
  • 我不认为你可以在不改变“技术”的情况下有意义地压缩代码。 IE。您可以进行一些类似正则表达式的验证或构建模式匹配的 DSL,但您所拥有的效果很好并且非常少
  • 我的 Visa 卡有 16 位数字。你确定这是对的吗?
  • if 语句中缺少括号,导致代码无法编译。

标签: c conditional-statements


【解决方案1】:

将其放入(静态)函数中。暂时不要考虑性能/优化。


static char *card_leng_type2string( unsigned len, int *arr)
{
if (len == 15 && arr[0] == 3 && arr[1] == 4 ) return "AMEX";
if (len == 15 && arr[0] == 3 && arr[1] == 7 ) return "AMEX";
 
if (len == 16 && arr[0] == 5 && arr[1] == 1 ) return "MASTERCARD";
if (len == 16 && arr[0] == 5 && arr[1] == 2 ) return "MASTERCARD";
if (len == 16 && arr[0] == 5 && arr[1] == 3 ) return "MASTERCARD";
if (len == 16 && arr[0] == 5 && arr[1] == 4 ) return "MASTERCARD";
if (len == 16 && arr[0] == 5 && arr[1] == 5 ) return "MASTERCARD";

if (len == 13 && arr[0] == 4) return "VISA";

return "INVALID";
}

现在你的调用代码可以这样做:

printf("%s\n", card_leng_type2string(cardLength, numberArray) );

【讨论】:

  • 我其实很喜欢这种情况下的重复表达——它们让一切变得更加清晰。我最初误读了原始代码,因为它调用了像 347 这样的序列。
  • 根据Wikipedia,VISA卡号可以是13或16个字符。美国运通卡和万事达卡看起来不错。
  • @SteveSummit:至少它更易于阅读和编辑。它可以在以后被重构(变成基于表的数据,或者返回一个枚举而不是一个常量字符串)
  • @LucaPolito :我不关心文字/常量。我只是试图复制/模仿问题的行为。
  • 将代码封装在函数中的建议几乎总是一个很好的建议。它不仅使调用代码更易于阅读,而且一旦你有一个封装的函数,就很容易围绕它进行单元测试,一旦你有了单元测试,你可以稍后重写函数(也许在“更多高效”但不太清晰的方式)而不受惩罚。
【解决方案2】:

您可以将numberArray 的前两位数字转换成这样的新数字

num = numberArray[0]*10 + numberArray[1]

然后将其用于条件语句中以使其更具可读性

int num = numberArray[0]*10 + numberArray[1]

if ((cardLength == 15) && ((num == 37) || (num == 34)))
{
    printf("AMEX\n");
}
else if ((cardLength == 16) && ((num >= 51) && (num <= 55)))
{
    printf("MASTERCARD\n");
}
else if ((cardLength == 13) && ((num >= 40) && (num <= 49)))
{
    printf("VISA\n");
}
else
{
    printf("INVALID\n");
}
return 0;
}

【讨论】:

  • 好主意,虽然它让读者摸不着头脑:为什​​么不是最后一个案例if(cardLength == 13 &amp;&amp; num == 4)
  • 另外,这个实现有一些小错误:初始num计算需要字符→数字转换;美国运通条款不应允许 35 和 36;万事达卡条款不应允许 56; VISA 子句需要检查'4' 而不是4,并且所有if 语句都需要另外一对括号。 (我猜你在发布之前没有编译它。:-))
  • @SteveSummit 你在大多数事情上都是对的。我更正了您发现的语法错误(是的,我没有编译它;-))
  • 最后一个case应该是numberArray[0] == 4而不是num &gt;= 40
  • @hmhuang num 是一个两位数,因为它由numberArray 的前两个元素组成。所以我们它的值必须在 40 到 49 之间
【解决方案3】:

假设numberArray 中的条目在0-9 范围内,您可以使用strchr 函数。如果给定字符串包含特定字符,则返回非 NULL。

替换:

numberArray[1] == 4 || numberArray[1] == 7 || numberArray[1] == 9

strchr("479", '0' + numberArray[1])

如果numberArray 是一个字符数组,那么检查可以简化为strchr("479", numberArray[1])

【讨论】:

    【解决方案4】:

    如果您希望逻辑完整并且只希望修改可读性,您可以尝试全局添加预处理器指令。 这将替换您在程序中使用的任何地方的文本或内联函数。 示例

    #define AMEX_CONDITION (cardLength == 15) &&  (numberArray[0] == 3 && (numberArray[1] == 4 || numberArray[1] == 7))
    

    并在你的 if as 中使用它

    if(AMEX_CONDITION){
        printf("AMEX");
    }
    

    【讨论】:

    • 这会降低可读性。我建议添加一些static inline 函数
    • 发明自己的秘密宏语言是一个非常糟糕的主意。这比 OP 已经拥有的要糟糕得多。
    • RE:宏的使用:根据我的经验,宏替换在软件工程(操作系统和实时、嵌入式系统)中很常见且有效...
    • @MartinKuester 我几乎只使用实时嵌入式系统,根据我的经验,当程序员忘记函数内联或现代编译器如何生成代码时,通常会使用此类宏。或者当他们以其他方式感到困惑时,例如发明一些神奇的宏语言只是为了进行简单的 GPIO 位操作。
    猜你喜欢
    • 1970-01-01
    • 2012-12-13
    • 2021-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-24
    • 2015-01-26
    相关资源
    最近更新 更多