如果条件适用于多行的良好C编码风格

时间:2015-03-29 12:10:14

标签: c if-statement conditional-statements lines

我正在用C语言编写一个项目并遇到问题:我有很多if条件,其他人可能很难阅读。我还没有在互联网上找到类似的问题。

您是否有想法或示例如何使我的代码更具可读性?

这是C代码:

if( ((g_cycle_cnt == uartTxSecondaryMsg[3][msgPos[3]].sliceNo) ||   //correct slicenumber...
    (uartTxSecondaryMsg[3][msgPos[3]].sliceNo == -1) ||             // or as fast as possible...                                            

  ( (uartTxSecondaryMsg[3][msgPos[3]].sliceNo == -2) &&
   ((uartTxSecondaryMsg[3][msgPos[3]].timeFrameBegin>=g_uptime_cnt) && 
    (uartTxSecondaryMsg[3][msgPos[3]].timeFrameEnd<=g_uptime_cnt)))) &&

   ((dataProcessingFlag & SECONDARY_MSG_ANNOUNCED_CH4) == SECONDARY_MSG_ANNOUNCED_CH4) )

6 个答案:

答案 0 :(得分:4)

创建具有指示性名称的功能,以检查要求并表示其含义,例如:

if( is_correct_slice_number(/*... params here ... */) || 
    is_asap(/*... params here ... */)  || 
    is_other_condition(/*... params here ... */))

或者建议的宏遵循相同的逻辑,例如:

if( IS_CORRECT_SLICE_NUMBER(/*... params here ... */) || 
    IS_ASAP(/*... params here ... */)  || 
    IS_OTHER_CONDITION(/*... params here ... */))

我认为这可能会让你的意图更清晰。

答案 1 :(得分:4)

如果您想坚持使用现有代码(而不是将内容放入内联函数中),只需修改缩进,我就是一直忠实使用indent的忠实粉丝。这意味着您可以修复任何源文件。

使用默认选项,它会为您提供GNU缩进,即:

if (((g_cycle_cnt == uartTxSecondaryMsg[3][msgPos[3]].sliceNo) ||       //correct slicenumber...
     (uartTxSecondaryMsg[3][msgPos[3]].sliceNo == -1) ||        // or as fast as possible...
     ((uartTxSecondaryMsg[3][msgPos[3]].sliceNo == -2) &&
      ((uartTxSecondaryMsg[3][msgPos[3]].timeFrameBegin >= g_uptime_cnt) &&
       (uartTxSecondaryMsg[3][msgPos[3]].timeFrameEnd <= g_uptime_cnt)))) &&
    ((dataProcessingFlag & SECONDARY_MSG_ANNOUNCED_CH4) ==
     SECONDARY_MSG_ANNOUNCED_CH4))
  {
    /* do something */
  }

我会说这里的问题实际上是你在数组中难以辨认。至少要考虑因素:

uartTxSecondaryMsg[3][msgPos[3]]

成一个单独的变量,例如:

whatever *foo = &uartTxSecondaryMsg[3][msgPos[3]];
if (((g_cycle_cnt == foo->sliceNo) ||   //correct slicenumber...
     (foo->sliceNo == -1) ||    // or as fast as possible...
     ((foo->sliceNo == -2) &&
      ((foo->timeFrameBegin >= g_uptime_cnt) &&
       (foo->timeFrameEnd <= g_uptime_cnt)))) &&
    ((dataProcessingFlag & SECONDARY_MSG_ANNOUNCED_CH4) ==
     SECONDARY_MSG_ANNOUNCED_CH4))
  {
    /* do something */
  }

显然,为foo选择合适的类型和变量名称。

然后,您可以将if语句的分支分成单独的函数,每个函数都以foo作为参数。

答案 2 :(得分:1)

这是非常主观的(即关于如何使这类事情变得更好,就像有人一样)。

我可能会使用一些额外的变量,例如

WhateverType  your_object = uartTxSecondaryMsg[3][msgPos[3]];
int slice = your_object.sliceNo;
int begin = your_object.timeFrameBegin;
int end = your_object.timeFrameEnd;

if ( (g_cycle_cnt = slice || slice == -1) ||
     (slice == -2 && begin >= g_uptime_cnt && end <= g_uptime_cnt) &&
      ((dataProcessingFlag & SECONDARY_MSG_ANNOUNCED_CH4) == SECONDARY_MSG_ANNOUNCED_CH4) )

(注意:我可能在上面提到了错误的括号。将其视为演示概念,而不是完整的解决方案。)

也可以使用评估特定部件的辅助函数。如果结构正确(并命名为右),这样的事情可以使您的代码更容易理解。

正如alk在回应这篇文章时所评论的那样,重要的是在方法和布局上要系统化。

答案 3 :(得分:1)

[这是非常主观的]

  • 删除多余的括号;他们是防御性的,模糊了意思
  • 正确对齐并排序条件(可能忽略缩进规则)
  • (也许)重写为另一个构造,例如switch,或使用早期return,甚至是goto

第一步(清理和对齐):

if (    (  uartTxSecondaryMsg[3][msgPos[3]].sliceNo == g_cycle_cnt //correct slicenumber...
        || uartTxSecondaryMsg[3][msgPos[3]].sliceNo == -1          // or as fast as possible...                                
        ||(uartTxSecondaryMsg[3][msgPos[3]].sliceNo == -2
             && uartTxSecondaryMsg[3][msgPos[3]].timeFrameBegin >= g_uptime_cnt
             && uartTxSecondaryMsg[3][msgPos[3]].timeFrameEnd <= g_uptime_cnt
             && (dataProcessingFlag & SECONDARY_MSG_ANNOUNCED_CH4) == SECONDARY_MSG_ANNOUNCED_CH4 ) ) 
                {
                // do something useful here
                }

第二步,使用switch(和goto!)[这对某些读者来说可能有点太多了......]

switch (uartTxSecondaryMsg[3][msgPos[3]].sliceNo) {
default:
    if (uartTxSecondaryMsg[3][msgPos[3]].sliceNo == g_cycle_cnt) goto process;
    break;
case -2:
    if (uartTxSecondaryMsg[3][msgPos[3]].timeFrameBegin < g_uptime_cnt) break;
    if (uartTxSecondaryMsg[3][msgPos[3]].timeFrameEnd > g_uptime_cnt) break;
    if ((dataProcessingFlag & SECONDARY_MSG_ANNOUNCED_CH4) != SECONDARY_MSG_ANNOUNCED_CH4) break;
case -1:
process:

          // do something useful here
 }

switch()构造的优势在于它立即清楚uartTxSecondaryMsg[3][msgPos[3]].sliceNo条件。另一个优点是可以添加案例和条件,而不必干涉其他案件或与括号斗争。

现在我希望我得到括号 - 删除权......

答案 4 :(得分:0)

这是为什么缩进如此重要的一个很好的例子。当我阅读其他人的解决方案时,我意识到有些人弄错了最后的&&子句。当我使用Notepad ++突出显示括号时,我发现最后的&&子句实际上处于最高级别,而大多数重写都将它与“ .... timeFrameEnd <= g_uptime_cnt”配对

此外,请看第三条,请注意(test_1 &&(test_2 && test_3))等同于(test_1 && test_2 && test_3),因此可以通过仅除去一层parens来清除某些复杂性。 / p>

我更喜欢示例C。

// Example A:
if (  (  (g_cycle_cnt == uartTxSecondaryMsg[3][msgPos[3]].sliceNo)  //correct slicenumber
      || (uartTxSecondaryMsg[3][msgPos[3]].sliceNo == -1)           // or as fast as possible...
      || (  (uartTxSecondaryMsg[3][msgPos[3]].sliceNo == -2)
         && (  (uartTxSecondaryMsg[3][msgPos[3]].timeFrameBegin>=g_uptime_cnt)
            && (uartTxSecondaryMsg[3][msgPos[3]].timeFrameEnd<=g_uptime_cnt))))
      && ((dataProcessingFlag & SECONDARY_MSG_ANNOUNCED_CH4) == SECONDARY_MSG_ANNOUNCED_CH4)
   ){
    // do something
}

// Example B
if ( ( (g_cycle_cnt == uartTxSecondaryMsg[3][msgPos[3]].sliceNo) ||   //correct slicenumber...
       (uartTxSecondaryMsg[3][msgPos[3]].sliceNo == -1) ||             // or as fast as possible...
       ( (uartTxSecondaryMsg[3][msgPos[3]].sliceNo == -2) &&
         ( (uartTxSecondaryMsg[3][msgPos[3]].timeFrameBegin >= g_uptime_cnt) &&
           (uartTxSecondaryMsg[3][msgPos[3]].timeFrameEnd <= g_uptime_cnt)))) &&

     ( (dataProcessingFlag & SECONDARY_MSG_ANNOUNCED_CH4) == SECONDARY_MSG_ANNOUNCED_CH4) 
   )
{
    // do something
}

// Example C
if( ( (g_cycle_cnt == uartTxSecondaryMsg[3][msgPos[3]].sliceNo) ||   //correct slicenumber...
      (uartTxSecondaryMsg[3][msgPos[3]].sliceNo == -1) ||             // or as fast as possible...
      ( (uartTxSecondaryMsg[3][msgPos[3]].sliceNo == -2) &&
        (uartTxSecondaryMsg[3][msgPos[3]].timeFrameBegin>=g_uptime_cnt) && 
        (uartTxSecondaryMsg[3][msgPos[3]].timeFrameEnd<=g_uptime_cnt)
      )
    ) &&
    ( (dataProcessingFlag & SECONDARY_MSG_ANNOUNCED_CH4) == SECONDARY_MSG_ANNOUNCED_CH4) 
  )
{
    // do something
}

答案 5 :(得分:0)

通过功能设计,您可以执行以下操作。如果需要,还可以使用else if结构,以使代码更加紧凑,但我更喜欢这样做。这样,水平代码最少。也许我看了太多的Linux内核代码。但是我认为这是内核空间中的人可以做到这一点的方式。

您的怪物是如此之大,以至于没人能跟随它。这种样式可以逐行检查,也可以在if语句之前添加注释。

void foo()
{
    if (dataProcessingFlag & SECONDARY_MSG_ANNOUNCED_CH4 != SECONDARY_MSG_ANNOUNCED_CH4)
        return;

    if (g_cycle_cnt == uartTxSecondaryMsg[3][msgPos[3]].sliceNo)
        goto out;

    if (uartTxSecondaryMsg[3][msgPos[3]].sliceNo != -2)
        return;

    if (uartTxSecondaryMsg[3][msgPos[3]].timeFrameBegin < g_uptime_cnt)
        return;

    if (uartTxSecondaryMsg[3][msgPos[3]].timeFrameEnd > g_uptime_cnt)
        return;
out:
    // Do something.

    // Another way is to call another function here and also in goto statement
    // That way you don't have to use goto's if do not want.
}