代码之家  ›  专栏  ›  技术社区  ›  ncenerar

是否可以#包含.c源文件以维护嵌入式c代码?

  •  28
  • ncenerar  · 技术社区  · 6 年前

    .c 另一个源文件被认为是不好的做法,但我有一种情况,我认为它可以帮助维护。

    #define 保留索引。

    #define TOTO_IND 0 
    #define TITI_IND 1 
    …
    #define TATA_IND 50
    
    static const MyElements elems [] = {
        {"TOTO", 18, "French"},
        {"TITI", 27, "English"},
        ...,
        {"TATA", 45, "Spanish"}
    }
    

    因为我需要从索引访问结构,所以我需要保留 与结构声明同步。这意味着我必须在正确的位置插入新元素并更新 #定义 相应地。

    无论如何,这个文件还包含很多函数来处理这个结构。我还想保持代码的分离,避免全局变量。

    为了让事情更简单,我想把这个容易出错的定义移到一个 只包含此结构的源文件。这个文件将是危险的小心文件,并包括在我的实际正常功能文件。

    你觉得怎么样?包括在内的情况是否有效 c 源文件?有没有其他更好的方法来处理我的结构?

    5 回复  |  直到 6 年前
        1
  •  33
  •   Lundin    6 年前

    typedef enum
    {
      TOTO_IND,
      TITI_IND,
      ...
      TATA_IND,
      TOTO_N    // this is not a data item but the number of items in the enum
    } toto_t;
    

    总成本

    const MyElements elems [] = {
      [TITI_IND] = {"TITI", 27, "English"},
      [TATA_IND] = {"TATA", 45, "Spanish"},
      [TOTO_IND] = {"TOTO", 18, "French"},
    };
    

    现在您可以使用静态断言来验证整个阵列的数据完整性:

    _Static_assert(sizeof elems/sizeof *elems == TOTO_N, 
                   "Mismatch between toto_t and elems is causing rain in Africa");
    

    _Static_assert(sizeof elems/sizeof *elems == TOTO_N, ERR_MSG);
    

    哪里 ERR_MSG

    #define STR(x) STR2(x)
    #define STR2(x) #x
    #define ERR_MSG "Mismatching toto_t. Holding on line " STR(__LINE__)
    
        2
  •  40
  •   Ian Abbott    6 年前

    可以使用指定的初始值设定项来初始化 elems[] 无需知道每个索引标识符(或宏)的显式值。

    const MyElements elems[] = {
        [TOTO_IND] = {"TOTO", 18, "French"},
        [TITI_IND] = {"TITI", 27, "English"},
        [TATA_IND] = {"TATA", 45, "Spanish"},
    };
    

    数组元素将以相同的方式初始化,即使更改它们在源代码中的显示顺序:

    const MyElements elems[] = {
        [TITI_IND] = {"TITI", 27, "English"},
        [TATA_IND] = {"TATA", 45, "Spanish"},
        [TOTO_IND] = {"TOTO", 18, "French"},
    };
    

    如果数组长度是从上述初始值设定项自动设置的(即使用 [] 而不是 [NUM_ELEMS]

    这允许您保留 elems 数组,并定义 元素 在一个单独的.c文件中数组内容。

        3
  •  18
  •   vgru    6 年前

    其他的答案已经以一种更清晰的方式涵盖了它,但为了完整性起见,这里有一个x-macros方法,如果你愿意走这条路,冒着同事的愤怒。

    X宏是一种代码生成形式,使用内置的C预处理器。目标是尽量减少重复,尽管有一些缺点:

    1. 如果您不习惯使用预处理器生成枚举和结构,那么使用预处理器生成枚举和结构的源文件可能看起来很复杂。
    2. 与生成源文件的外部构建脚本相比,使用x宏时,除非使用编译器设置并手动检查预处理的文件,否则在编译期间您永远看不到生成的代码是什么样子的。
    3. 因为看不到预处理的输出,所以不能像处理外部脚本生成的代码那样使用调试器单步执行生成的代码。

    首先创建一个宏列表 调用 在一个单独的文件中,例如。 elements.inc ,而不定义宏此时实际执行的操作:

    // elements.inc
    
    // each row passes a set of parameters to the macro,
    // although at this point we haven't defined what the
    // macro will output
    
    XMACRO(TOTO, 18, French)
    XMACRO(TITI, 27, English)
    XMACRO(TATA, 45, Spanish)
    

    // concatenate id with "_IND" to create enums, ignore code and description
    // (notice how you don't need to use all parameters each time)
    // e.g. XMACRO(TOTO, 18, French) => TOTO_IND,
    #define XMACRO(id, code, description) id ## _IND,
    typedef enum
    {
    #    include "elements.inc"
         ELEMENTS_COUNT
    }
    Elements;
    #undef XMACRO
    
    // create struct entries
    // e.g. XMACRO(TOTO, 18, French) => [TOTO_IND] = { "TOTO", 18, "French" },
    #define XMACRO(id, code, description) [id ## _IND] = { #id, code, #description },
    const MyElements elems[] = {
    {
    #    include "elements.inc"
    };
    #undef XMACRO
    

    它会被预处理成:

    typedef enum
    {
        TOTO_IND,
        TITI_IND,
        TATA_IND,
        ELEMENTS_COUNT
    }
    Elements;
    
    const MyElements elems[] = {
    {
        [TOTO_IND] = { "TOTO", 18, "French" },
        [TITI_IND] = { "TITI", 27, "English" },
        [TATA_IND] = { "TATA", 45, "Spanish" },
    };
    

    显然,列表的频繁维护变得更容易,而生成的代码变得更复杂。

        4
  •  5
  •   Joshua Kim nkhar    6 年前

    定义 const 作为 static 在多个文件中,这不是一个好主意,因为它会创建大变量的多个实例 MyElements . 这将增加嵌入式系统的内存。这个 需要删除限定符。

    以下是建议的解决方案:

    在文件.h中

    #define TOTO_IND 0 
    #define TITI_IND 1 
    …
    #define TATA_IND 50
    #define MAX_ELEMS 51
    
    extern const MyElements elems[MAX_ELEMS];
    

    #include "file.h"
    const MyElements elems [MAX_ELEMS] = {
        {"TOTO", 18, "French"},
        {"TITI", 27, "English"},
        ...,
        {"TATA", 45, "Spanish"}
    }
    

    #include "file.h" 在所需的.c文件中。

        5
  •  1
  •   shogged    6 年前

    解决有关使用 #include .c

    一切都在一个 c #extern . 例如,你可以用 #extern const MyElements elems []; 在你的主要 c 文件。

    .h #包括 h 由约定使用,大多数IDE将自动添加 c 文件到要编译的文件列表,但就编译器而言,命名是任意的。