【问题标题】:Compile only specific part of code when they are used使用时仅编译代码的特定部分
【发布时间】:2020-01-04 02:52:36
【问题描述】:

我必须进行条件编译以在不使用某些代码时跳过它们。该项目是一个MCU项目,由LED、LCD、键盘等外部模块组成。

我有一个optimization.h 文件,用于告诉编译时使用了哪些模块。是这样的……

#ifndef OPTIMIZATION_H
#define OPTIMIZATION_H

// 1 - Compile code only for given modules
// 0 - Compile for all available modules
#define _OPTIMIZE_ 1

// Modules to compile
#define _LED_    1
#define _SWITCH_ 1

// Modules not to compile
#define _LCD_    0
#define _SSD_    0

#endif

code.c 文件是这样的...

#include "optimization.h"
void myFun()
{
// Compile when LED is used or all modules are asked to use
// i.e when _OPTIMIZE_ is 0 or _LED_ is 1

// Need to compile this code
#if !(_OPTIMIZE_) || (_LED_)
/* My code goes here */
#endif

// Need to compile this code
#if !(_OPTIMIZE_) || (_SWITCH_)
/* My code goes here */
#endif

// Need not to compile
#if !(_OPTIMIZE_) || (_LCD_)
/* My code goes here */
#endif

// Need not to compile
#if !(_OPTIMIZE_) || (_SSD_)
/* My code goes here */
#endif
}

如果我只想使用 LED 和 SWITCH,则只需编译该部分代码。但是每次都会编译所有模块。可能是什么问题...

【问题讨论】:

  • Works For Me™。您是否打印了OPTIMIZE 和朋友以使他们符合您的期望?此外,good editor 将指示您未遵循哪些路径。
  • 你(或我们)怎么知道它们被编译了?请生成minimal reproducible example
  • 看起来它应该可以正常工作,除了 iirc,带有前导下划线的预处理器变量是为编译器保留的。可能会发生一些奇怪的定义冲突。您应该选择其他名称。您可以尝试使用#if _VAR_ \n #error Var was true! \n #endif 进行调试。此外,不需要 #if 指令中的括号。最后,您应该考虑一种完全不同的方法。将函数拆分为单独的文件并管理在 makefile 中编译的内容。从长远来看,这更清洁。
  • 请注意,一般情况下,您不应创建以下划线开头的函数、变量、标记或宏名称。 C11 §7.1.3 Reserved identifiers 的一部分说: — 所有以下划线开头的标识符以及大写字母或另一个下划线始终保留供任何使用。所有以下划线开头的标识符始终保留保留在普通和标记名称空间中用作具有文件范围的标识符。 另见What does double underscore (__const) mean in C?
  • 不要相信 IDE 着色来进行调试/测试。如果您想知道是否编译了某些内容,请在其中写一个#error Yes, it gets compiled!,它会清楚地告诉您。

标签: c microcontroller


【解决方案1】:

正确的解决方案是创建一个包含所有功能的库。将您的程序与该库链接,只有需要的函数才能将其放入生成的二进制文件中。

为此,您需要将每个函数放入其自己的编译单元中。您可以通过单独的源文件或使用基于预处理器宏的选择和每个选项一个编译命令的单个源文件来执行此操作。我宁愿选择第一种方式。

【讨论】:

  • 在编译器中启用“每个函数一个 ELF 节”选项也有帮助
  • 像真正的 CS 毕业生一样说话。虽然这个建议可能非常适合应用程序级编程,但它不太适合低级编程,例如嵌入式系统或操作系统/平台代码,为了提高效率,必须保持最少。您建议的样式导致调用树比其他方式可能需要的更深。如果您的操作系统并且 C++ 运行时以典型的应用程序编程风格进行编程,你会从中获得更差的性能。在资源严重受限的嵌入式系统上,使用这种编程风格,您会很快耗尽代码空间或堆栈空间。
  • @phonetagger 我不同意。自 30 多年以来,我一直在使用嵌入式系统,其中 90% 以上的时间都在使用 MCS51,这是最有限的平台之一。如果你离性能和空间的边界这么近,你宁愿使用汇编程序。而且 OP 说的是 LED 和按键,不需要性能。
  • MCS51,你不是没有空间了吗?有趣...我的公司生产电表,使用具有集成 8051 内核和存储内存的 Silergy 部件,因此我们可以超过 64K,我们还有一款仍在生产中的旧产品,具有积极的功能开发和不到 20 字节的可用 RAM (当我们重构以减少使用时,确切的数量会上下波动)。
  • 就您的建议而言,如果您已经有单独的函数,当然……我的意思是,如果您的代码空间有限,使用条件编译和更大的函数通常会占用更少的代码空间并导致如果您遵循典型的应用程序编程实践,将较大的函数拆分为微小的片段函数,每个片段函数都专注于算法的一个微小方面,那么堆栈深度会更浅。
【解决方案2】:

恐怕您的问题过于简化,因此我们无法提供帮助。以下代码在我的机器上运行良好:

#include <stdio.h>
/*** from Optimize.h ***/

// 1 - Compile code only for given modules
// 0 - Compile for all available modules
#define _OPTIMIZE_ 1

// Modules to compile
#define _LED_    1
#define _SWITCH_ 1

// Modules not to compile
#define _LCD_    0
#define _SSD_    0

/*** from Code.c **/
int main()
{
// Need to compile this code
#if !(_OPTIMIZE_) || (_LED_)
    printf ("Module LED included\n");
#endif

// Need to compile this code
#if !(_OPTIMIZE_) || (_SWITCH_)
    printf ("Module SWITCH included\n");
#endif

// Need not to compile
#if !(_OPTIMIZE_) || (_LCD_)
    This line is invalid C code.
    printf ("Module LCD included\n");
#endif
}

另外,我建议重命名您的预处理器变量。你应该写#if INCLUDE_ALL_MODULES || INCLUDE_LCD_MODULE,而不是难以阅读的#if !(_OPTIMIZE_) || (_LCD_)。还可以考虑使用构造 #define INCLUDE_LCD_MODULE (INCLUDE_ALL_MODULES | 1)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多