config.h 文件中带有变量的库

A library with variable in config.h file

我正在编写一个库,其中用户必须在 config.h 文件中声明他自己的变量。

这个库有三个文件:主文件 lib.c.h 文件、lib.h 和配置文件:config.h。对于所有库,用户只能更改 config.h 文件。他必须声明他需要的一组数字。问题是我们无法在 .h 个文件中初始化数组。

我想到的一个解决方案是,用户将他的数组和sizeof他的数组作为参数传递给我所有的lib.c函数,但我想知道标准是什么?专业程序员在其他图书馆做什么? (编辑lib.c 包含 lib.hlib.c 包含 config.h 文件。)

注意:用户需要的数组,是常量。他只需定义一次并将其传递给所有函数。这就是为什么我想在 config.h 文件中初始化数组(这样它只被声明一次)。 (不用说 sizeof 数组也是常量。)

config.h 文件:

#define BTN0    {BTN0_GPIO_Port, BTN0_Pin} //user defines these
#define BTN1    {BTN1_GPIO_Port, BTN1_Pin}

typedef struct {
    GPIO_TypeDef* port;
    uint16_t pin;
} btn;

const btn btns[] = {BTN0, BTN1};

#define BUTTON_ARR_SIZE     sizeof(btns)/sizeof(btns[0])
#define BUTTON_NOT_FOUND    BUTTON_ARR_SIZE //returns btn[n] which is not available. I use this line of definition in my library, and user needs it in his code.

lib.c 文件中:

bool checkPressAndReleaseUsingMask(btn button){ //private function. User doesn't call it.
    if (HAL_GPIO_ReadPin(button.port, button.pin) == GPIO_PIN_RESET) {
        while (HAL_GPIO_ReadPin(button.port, button.pin) == GPIO_PIN_RESET)
            osDelay(20);
        return 1;
    }
    return 0;
}

uint32_t find1Btn(){
    uint32_t whichBtn = BUTTON_NOT_FOUND;
    for (uint8_t i = 0; i < BUTTON_ARR_SIZE; i++){
        if(checkPressAndReleaseUsingMask(btns[i])){
            whichBtn = i;
            break;
        }
    }
    return whichBtn;
}
//bla bla bla

lib.h:

#include "config.h"
#include <stdint.h>
uint32_t find1Btn(void);

用户代码:

        int x = find1Btn();
        if(x != BUTTON_NOT_FOUND){ //No button is pressed
            //do sth.
        }

but I want to know what is the standard?

没有标准。

config.h 通常在 autotools-ish projects.

中生成

What do professional programmers do in other libraries?

千方百计。 有管理配置的 IDE。 有build systems and most probably each and every solution has its own different interface to manage project configuration Linux kernel has built it's whole big kconfig。 CMake 有命令行选项,甚至 cmake-gui。提到的 GNU autotools 有 ./configure --enable-this --disable-that 并且它生成 config.h 文件。许多简单的库只是有一个用户可定制的 header,就像你提议的那样。

请注意,使用中央单个 header 文件将(几乎)不可能在同一项目中使用不同配置多次使用同一库。如果使用静态 header 名称,我只建议选择与如此常见的 config.h 不同的名称。我喜欢使用分散的位置,比如 library-user-config.h 或类似的东西 - 配置 header 是特定于该库的,其他库不需要它。或者可能使用集中位置 - 这都是项目特定的。

由于 GPIO_TypeDef,您很可能在某些 stm32 上编程。您可能想了解其他嵌入式软件如何处理项目配置。浏览 github 寻找我喜欢的 many CMake and other libraries and build systems. Research MBed with its big mbed_config.h file. See Zephyr 并使用 CMake 和 west.

发现 Kconfig

He has to define it just once

在你的 header 文件中你做了 const btn btns[] 这意味着它将在 #include <config.h> 的每个文件中定义。要定义一次,请执行 extern const btn btns[2]; 并执行 const btn btns[] = ....config.c。要将定义保留在 header 中,允许多个定义 - 添加 static,例如 static const btn btns[] = ...

btn 结构定义看起来很漂亮 not-user-changable。我相信结构定义属于 lib.h,因为我怀疑用户会更改它。为避免名称冲突,请使用带有通用字符串的“命名空间”/前缀符号 - 如 btn_find1BTN_BUTTON_ARR_SIZE。宏 BUTTON_NOT_FOUND 对我来说似乎毫无意义,它不是用户配置的一部分——它是一个常量,可能只是 UINT32_MAX-1uint8_t i = 0; - 我会说更喜欢 size_t 来表达数组中的大小和索引。并且 int x = find1Btn(); - 请注意 find1Btn returns 和 uint32_t 而不是 int,转换可能会更改值。此外,数组 btns 可以排序(可能你可以使用一些代码生成器工具,如提到的构建系统(如 CMake),或 Python (Jinja2)或 m4 或其他)并使用 bsearch 以加快代码速度。