简体   繁体   English

多行的良好 C 编码风格 if 条件

[英]Good C-coding style for multiple lines if conditions

I am programming a project in C and have a problem: I've got a lot of if conditions and it might get really hard for other people to read.我正在用 C 编写一个项目并遇到一个问题:我有很多if条件,其他人可能很难阅读。 I haven't yet found a similar question on the internet.我还没有在互联网上找到类似的问题。

Do you have an idea or example how to make my code more readable?您有什么想法或示例如何使我的代码更具可读性吗?

Here is the C Code:这是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) )

Create functions that have indicative names that check the requirements and represent their meaning eg:创建具有检查要求并表示其含义的指示性名称的函数,例如:

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

Or as suggested macros that follow the same logic eg:或者作为遵循相同逻辑的建议宏,例如:

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

I think that this might make your intentions clearer.我认为这可能会使您的意图更加清晰。

If you want to stick with your existing code (as opposed to factor things out into inline functions), and just modify the indentation, I'm a big fan of using indent consistently.如果您想坚持使用现有代码(而不是将内容分解为内联函数),并且只是修改缩进,我非常喜欢始终使用indent This means you can fix any source file.这意味着您可以修复任何源文件。

With its default options it gives you GNU indentation, ie:它的默认选项为您提供 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 */
  }

I'd say that the problem here is in fact that you are poking about illegibly in arrays.我会说这里的问题实际上是你在数组中难以辨认。 At the very least, factor out:至少,考虑一下:

uartTxSecondaryMsg[3][msgPos[3]]

into a separate variable, eg:成一个单独的变量,例如:

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 */
  }

Obviously choose an appropriate type and variable name for foo .显然,为foo选择合适的类型和变量名。

You could then separate out the limbs of the if statement into separate functions each taking foo as a parameter.然后,您可以将if语句的分支分离为单独的函数,每个函数都将foo作为参数。

[this is very subjective] 【这个很主观】

  • remove excessive parentheses;删除过多的括号; they are defensive and obscure the meaning他们是防御性的,模糊了意义
  • properly align and order the conditions (possibly ignoring indentation rules)正确对齐和排序条件(可能忽略缩进规则)
  • (maybe) rewrite into another construct, such as a switch , or using early return s, or even goto (也许)重写为另一个结构,例如switch ,或使用 early return ,甚至goto

First step (cleanup and alignment):第一步(清理和对齐):

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
                }

Second step, using switch (and goto !) [this could be a bit too much for some readers ...]第二步,使用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
 }

The advantage of the switch() construct is that it immediately clear that uartTxSecondaryMsg[3][msgPos[3]].sliceNo is the master condition. switch()结构的优点是立即清楚uartTxSecondaryMsg[3][msgPos[3]].sliceNo条件。 Another advantage is that cases and conditions can be added without having to interfere with the other cases or to struggle with the parentheses.另一个优点是可以添加案例和条件,而不必干扰其他案例或与括号斗争。

Now I hope I got the parentheses-removal right...现在我希望我能正确删除括号......

This is a great example of why indentation is so important.这是为什么缩进如此重要的一个很好的例子。 As I was reading through other people's solutions, I realized some people got the last && clause wrong.当我阅读其他人的解决方案时,我意识到有些人弄错了最后一个 && 子句。 When I used Notepad++ to highlight the parens, I discovered that the last && clause was actually at the highest level, whereas most of the re-writes had it paired with "....timeFrameEnd<=g_uptime_cnt"当我使用 Notepad++ 突出显示括号时,我发现最后一个 && 子句实际上处于最高级别,而大多数重写都将它与“....timeFrameEnd<=g_uptime_cnt”配对

Also, looking at the third clause notice that (test_1 && (test_2 && test_3)) is equivalent to (test_1 && test_2 && test_3), so some of the complication can be cleaned up by just removing a layer of parens.此外,查看第三个子句注意 (test_1 && (test_2 && test_3)) 等价于 (test_1 && test_2 && test_3),因此只需删除一层括号就可以清除一些复杂性。

I prefer Example C.我更喜欢示例 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
}

This is really subjective (ie there is almost as many opinions on how to make this sort of thing better as there are people).这确实是主观的(即,关于如何使这种事情变得更好的意见几乎与人数一样多)。

I'd probably use a couple of extra variables, such as我可能会使用一些额外的变量,例如

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) 
   )

With function design you can do something like this.通过功能设计,您可以做这样的事情。 If you want you can also use else if structure so that code is tighter but I prefer this.如果你愿意,你也可以使用 else if 结构,这样代码更紧凑,但我更喜欢这个。 This way horizontal code is minimal.这种方式水平代码是最小的。 Maybe I have watch too much Linux kernel code.也许我看了太多 Linux 内核代码。 But I think this is the way someone in kernel space can make this.但我认为这是内核空间中的某个人可以做到的方式。

Your if is so monsteres that nobody could ever follow it.你的假设是如此的怪物,以至于没有人能够追随它。 This style you can check line by line and also add comments before if statements if needed.这种样式您可以逐行检查,如果需要,还可以在 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.
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM