nce*_*rar 29 c embedded maintainability performance stm32
我不是专业的C程序员,我知道包括.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"}
}
Run Code Online (Sandbox Code Playgroud)
因为我需要从索引访问结构,所以我需要保持#define和结构声明同步.这意味着我必须在正确的位置插入新元素并相应地更新#define.
它容易出错,我不喜欢它(但出于性能考虑,我找不到更好的解决方案).
无论如何,这个文件还包含很多处理这个结构的函数.我还希望保持代码分离并避免全局变量.
为了使事情变得"更容易",我正在考虑将这个"容易出错的定义"转移到.c仅包含此结构的单个源文件中.这个文件将是"危险的小心文件",并将其包含在我的实际"正常功能"文件中.
你怎么看待这件事?包含.c源文件是否有效?还有另一种更好的方法来处理我的结构吗?
Ian*_*ott 39
您可以使用指定的初始值设定项来初始化元素,elems[]而无需知道每个索引标识符(或宏)的显式值.
const MyElements elems[] = {
[TOTO_IND] = {"TOTO", 18, "French"},
[TITI_IND] = {"TITI", 27, "English"},
[TATA_IND] = {"TATA", 45, "Spanish"},
};
Run Code Online (Sandbox Code Playgroud)
即使您更改它们在源代码中出现的顺序,数组元素也将以相同的方式初始化:
const MyElements elems[] = {
[TITI_IND] = {"TITI", 27, "English"},
[TATA_IND] = {"TATA", 45, "Spanish"},
[TOTO_IND] = {"TOTO", 18, "French"},
};
Run Code Online (Sandbox Code Playgroud)
如果如上所述从初始化程序自动设置数组长度(即通过使用[]而不是[NUM_ELEMS]),则长度将比最大元素索引多一个.
这允许您将elems数组的索引值和外部声明保留在.h文件中,并elems在单独的.c文件中定义数组内容.
Lun*_*din 33
你应该使用指定的初始化器,如Ian Abbot的答案所示.
此外,如果数组索引相邻,就像这里的情况一样,您可以使用枚举:
toto.h
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;
Run Code Online (Sandbox Code Playgroud)
toto.c
const MyElements elems [] = {
[TITI_IND] = {"TITI", 27, "English"},
[TATA_IND] = {"TATA", 45, "Spanish"},
[TOTO_IND] = {"TOTO", 18, "French"},
};
Run Code Online (Sandbox Code Playgroud)
现在,您可以使用静态断言验证整个数组的数据完整性:
_Static_assert(sizeof elems/sizeof *elems == TOTO_N,
"Mismatch between toto_t and elems is causing rain in Africa");
Run Code Online (Sandbox Code Playgroud)
_Static_assert(sizeof elems/sizeof *elems == TOTO_N, ERR_MSG);
Run Code Online (Sandbox Code Playgroud)
在哪里ERR_MSG定义为
#define STR(x) STR2(x)
#define STR2(x) #x
#define ERR_MSG "Mismatching toto_t. Holding on line " STR(__LINE__)
Run Code Online (Sandbox Code Playgroud)
Gro*_*roo 18
其他答案已经以更清晰的方式涵盖了它,但为了完整起见,这里有一个x-macros方法,如果你愿意沿着这条路走下去并冒着你同事的风险.
X-macro是一种代码生成形式,使用内置的C预处理器.目标是尽量减少重复,尽管有一些缺点:
首先,在单独的文件中创建宏调用列表,例如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)
Run Code Online (Sandbox Code Playgroud)
然后在每次需要包含此列表时定义宏,以便每次调用都呈现为您要创建的构造的单行 - 并且您通常连续多次重复此行,即
// 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
Run Code Online (Sandbox Code Playgroud)
哪个将被预处理成类似的东西:
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" },
};
Run Code Online (Sandbox Code Playgroud)
显然,频繁维护列表变得更容易,代价是生成代码变得更复杂.
在多个文件中定义constas static并不是一个好主意,因为它会创建大变量的多个实例MyElements.这将增加嵌入式系统的内存.在static预选赛中需要删除.
这是一个建议的解决方案:
在file.h中
#define TOTO_IND 0
#define TITI_IND 1
…
#define TATA_IND 50
#define MAX_ELEMS 51
extern const MyElements elems[MAX_ELEMS];
Run Code Online (Sandbox Code Playgroud)
在file.c中
#include "file.h"
const MyElements elems [MAX_ELEMS] = {
{"TOTO", 18, "French"},
{"TITI", 27, "English"},
...,
{"TATA", 45, "Spanish"}
}
Run Code Online (Sandbox Code Playgroud)
修改后,放入#include "file.h"所需的.c文件.
| 归档时间: |
|
| 查看次数: |
4266 次 |
| 最近记录: |