嵌入式编程中宏值之间的比较是不是不好?

Posted

技术标签:

【中文标题】嵌入式编程中宏值之间的比较是不是不好?【英文标题】:Are comparison between macro values bad in embedded programming?嵌入式编程中宏值之间的比较是否不好? 【发布时间】:2014-12-11 14:47:23 【问题描述】:

我正在构建一个需要在 ARM 上运行的程序。 处理器有足够的资源来运行程序,所以这个问题与这类处理器没有直接关系,而是与资源和计算能力“有限”的非强大处理器有关。

为了打印调试信息(甚至激活部分代码),我使用了一个头文件,我在其中定义了设置为 true 或 false 的宏,如下所示:

#define DEBUG_ADCS_OBC true

在主程序中:

if (DEBUG_ADCS_OBC == true) 
    printf("O2A ");
    for (j = 0; j < 50; j++) 
        printf("%x ", buffer_obc[jj]);
    

这是一个坏习惯吗?有没有更好的方法来做到这一点?

此外,这些 IF 检查是否会以可衡量的方式影响性能?

或者可以安全地假设在编译代码时,IF 会以某种方式从流中移除,因为比较是在两个无法更改的值之间进行的?

【问题讨论】:

您应该 #ifdef 代码而不是值上的 if。 与其说是处理器能力的问题,不如说是编译器的能力(优化能力)问题。 您在if 语句中包含printf,并且您担心if 的性能? printf 花费的时间大约是 if 的数十亿倍。 @Borgleader:许多编译器将忽略if 分支的代码生成,这些分支总是返回false,但仍会验证语法。如果知道自己正在使用这样的编译器,那么在方法中使用if 而不是#ifdef 可能有助于避免嵌套#ifdef 构造和嵌套大括号时因独立处理而导致的一些讨厌的陷阱。 【参考方案1】:

由于表达式DEBUG_ADCS_OBC == true 可以在编译时求值,优化编译器将确定分支要么总是被采用,要么总是被绕过,并完全消除条件。因此,当您使用优化的编译器时,表达式的运行时间成本为零。

如果您在关闭所有优化的情况下进行编译,请改用条件编译。这将与优化编译器对常量表达式执行的操作相同,但在预处理器阶段。因此,即使关闭优化,编译器也不会“看到”条件。

注意 1: 由于 DEBUG_ADCS_OBC 具有布尔变量的含义,因此使用 DEBUG_ADCS_OBC 而不使用 == true 以获得更清晰的外观。

注意 2: 与其在程序主体中定义值,不如考虑在命令行上传递一个值,例如 -DDEBUG_ADCS_OBC=true。这使您可以在不修改源代码的情况下更改调试设置,只需操作 make 文件或其选项之一。

【讨论】:

我同意注释 1。如果(较旧的)编译器使用 _Bool 以外的类型作为 bool,则对 var == true 的测试不仅是多余的,而且很危险。它和写var == true == true == true == true一样有用。 我不得不说,为了清楚起见,我省略了一个细节:代码实际上是这个 #define DEBUG_ADCS_OBC True 并且 True 是在另一个标题中定义的。我没有为 bool 值使用任何标准库。如果这有帮助的话。【参考方案2】:

每当您的程序到达这一行时,都会评估您正在使用的代码。由于 DEBUG_ADCS_OBC 的每次更改都需要重新编译代码,因此您应该改用 #ifdef/#ifndef 表达式。它们的优点是,它们只在编译时被评估一次。

您的代码段可能如下所示:

标题:

//Remove this line if debugging should be disabled
#define DEBUG_DCS_OBS

来源:

#ifdef DEBUG_DCS_OBS

printf("O2A ");
for (j = 0; j < 50; j++) 
    printf("%x ", buffer_obc[jj]);


#endif

【讨论】:

只有在关闭优化的情况下才会每次评估。【参考方案3】:

让编译器执行此操作的问题是对常量表达式进行不必要的运行时测试。优化编译器会删除它,但同样它可能会发出有关常量表达式的警告,或者当宏未定义时,发出有关无法访问的代码的警告。

这不是“嵌入式编程不好”的问题,它在任何编程领域都没有什么优点。

以下是更通常的习惯用法,不会在最终构建中包含无法访问的代码,并且在适当配置的语法突出显示编辑器或 IDE 中通常会显示哪些代码部分是活动的,哪些是活动的不是。

#define DEBUG_ADCS_OBC

...

#if defined DEBUG_ADCS_OBC
    printf("O2A ");
    for (j = 0; j < 50; j++) 
    
        printf("%x ", buffer_obc[jj]);
    
#endif

【讨论】:

【参考方案4】:

我将添加一件没有提到的事情。

如果在调试版本中禁用优化,并且即使运行时性能影响微不足道,仍会包含代码。因此,调试版本通常比发布版本大。

如果您的内存非常有限,您可能会遇到发布版本适合设备内存而调试版本不适合的情况。

出于这个原因,我更喜欢编译时间#if 而不是运行时间if。我可以让调试和发布版本之间的内存使用更接近,并且在项目结束时继续使用调试器更容易。

【讨论】:

【参考方案5】:

优化器将解决其他回复中提到的额外资源问题,但我想补充一点。从代码可读性的角度来看,这段代码会重复很多次,因此您可以考虑创建您的特定打印宏。这些宏应该包含在调试启用或禁用宏中。

#ifdef DEBUG_DCS_OBS
myCustomPrint    //your custom printing code
#else
myCustomPrint    //No code here
#end

这也将降低宏在任何文件中被遗忘的可能性,这将导致真正的优化问题。

【讨论】:

以上是关于嵌入式编程中宏值之间的比较是不是不好?的主要内容,如果未能解决你的问题,请参考以下文章

嵌入式C/C++编程修养

嵌入式C语言

驱动编程思想之初体验 --------------- 嵌入式linux驱动开发之点亮LED

嵌入式软件异步编程:冥想

OraclePLSQL编程

metaRTC嵌入式webrtc编程指南