发表于: 2019-4-17 10:31:39 | 显示全部楼层

大多数情况下,软件需要某种方式来配置:根据设置,软件会做不同的事情。例如,在Raspberry的微控制器上运行的软件可能会带有一个OLED LCD屏,也可能不带:

raspberry-pi-and-tink22-with-oled-lcd.png

带OLED LCD的Raspberry Pi和tinyK22


我如何在我的应用程序代码中处理这个问题?


变量Variable

例如,如果运行时可以使用某个功能,我可以在应用程序中检查某个变量:

  1. extern bool configHas_LCD = true;
  2. ...
  3. if (configHas_LCD) {
  4.   showStatusOnLCD();
  5. }
复制代码

该方法将在运行时决定是否执行。它需要更多的内存,执行时间更长。


文件

在带有文件系统的项目中,可以将配置存储在文件中,这样做会很有效。可以使用.ini实用程序。使用此配置,设置可以存储在文本文件的[sections]中:

  1. [Configuration]
  2. LCD = Yes
复制代码

然后我可以像这样使用它:

  1. configHas_LCD = MINI1_ini_bool("Configuration", "LCD", false, "config.ini");
  2. if (configHas_LCD) {
  3.   showStatusOnLCD();
  4. }
  5. }
复制代码

通过这种方法,我可以从“外部”配置应用程序:非常灵活,但当然会带来一些开销。


Constant常量

如果配置不改变,更好的方法是使用常量:

  1. const bool configHas_LCD = true;
  2. ...
  3. if (configHas_LCD) {
  4.   showStatusOnLCD();
  5. }
复制代码

这种方式更好,编译器能够“‘constant-folding”,并且应用程序中不会出现额外的比较代码。


#define定义

我更喜欢使用一些配置宏定义:

  1. #define CONFIG_HAS_LCD   (1)
  2.   /*!< 1: we have the LCD available. 0: no LCD available */

  3. ...
  4. #if CONFIG_HAS_LCD
  5. showStatusOnLCD();
  6. #endif
复制代码

最好是将这些配置宏放在专用的头文件中:

  1. /* config.h */
  2. #define CONFIG_HAS_LCD (1)
  3.   /*!< 1: we have the LCD available. 0: no LCD available */
复制代码

然后在应用程序中包含该头文件。


编译器-D选项

另一种方法是使用编译器-D(定义)选项。

  1. -DCONFIG_HAS_LCD=1
复制代码

和在源代码中使用以下方法的效果相同

  1. #define CONFIG_HAS_LCD   1
复制代码

在Eclipse中,可以在项目设置中添加定义:

compiler-d-option.png

编译器-D选项


我不喜欢这种方式,因为这样设置被“隐藏”在项目设置中。使用版本控制系统时,可能很难看到这种变化。


-include编译器选项

我更喜欢使用-include编译器选项:使用该选项我可以为编译的每个源文件包含一个头文件。


该选项在https://gcc.gnu.org/onlinedocs/g ... reprocessor-Options中描述:

-include file:
process file as if #include "file" appeared as the first line of the primary source file. However, the first directory searched for file is the preprocessor’s working directory instead of the directory containing the main source file. If not found there, it is searched for in the remainder of the #include "..." search chain as normal.

我可以在make文件中使用该选项或在IDE中设置它:

include-option.png

- include选项


请注意,我正在使用头文件的相对路径:

  1. "${ProjDirPath}/source/config.h"
复制代码

只需使用'config.h'就可以了。但Eclipse CDT中有一个长期未解决的错误,Eclipse Indexer如何处理-include选项。如果没有扩展的路径,Eclipse CDT会显示有关“unresolved inclusion”的恼人警告:

unresolved-inclusion.png

未解决的包含警告


多级配置

当然,有很多方法可以实现配置。以下是我的首选方式:


每个驱动程序或模块都有一个外部配置文件。例如LCD.c和LCD.h,LCD的配置在configLCD.h中

  1. /* configLCD.h */
  2. #ifndef CONFIGLCD_H_
  3. #define CONFIGLCD_H_

  4. #ifndef CONFIG_HAS_LCD
  5.   #define CONFIG_HAS_LCD (0)
  6. #endif

  7. #endif
复制代码

如果需要,我可以使用该配置头文件中的设置配置驱动程序。此配置头文件包含在LCD驱动程序中:

  1. /* LCD.c */
  2. #include "configLCD.h
  3. #include "LCD.h"
  4. ...
  5. #if CONFIG_HAS_LCD
  6.   showStatusOnLCD();
  7. #endif
  8. ...
复制代码

请注意,配置头文件中的配置#defines正在设置默认值,以防宏*未定义*(#ifndef)。因此,如果不想修改该文件,我可以使用-D编译器选项来更改设置。


或者:使用-include包含如下所示的头文件:

  1. /* config.h */
  2. #define CONFIG_HAS_LCD (1) /* enable LCD support */
复制代码

有了这个,我可以覆盖或配置驱动程序,而无需修改驱动程序配置头文件。 如果我有许多驱动程序或让它们由多个项目共享,这将非常有用:驱动程序可以与其默认配置文件一起共享,而我使用-include文件设置和覆盖内容。


总结

有许多方法可以在编译或运行时配置软件。 对于大多数应用程序,我更喜欢将#define宏与-include选项结合使用。

跳转到指定楼层
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题 47 | 回复: 68



手机版|

GMT+8, 2024-4-19 21:42 , Processed in 0.147845 second(s), 8 queries , Gzip On, MemCache On. Powered by Discuz! X3.5

YiBoard一板网 © 2015-2022 地址:河北省石家庄市长安区高营大街 ( 冀ICP备18020117号 )

快速回复 返回顶部 返回列表