我正在用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) )
答案 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.
}