将函数指针表的索引与表内容同步
在我正在开发的嵌入式系统中,我们使用函数指针表来支持专有的动态库。
我们有一个头文件,它使用命名常量(#define
)作为函数指针索引。这些值用于计算函数地址表中的位置。
示例:
(export_table.c)
// Assume each function in the table has an associated declaration
typedef void (*Function_Ptr)(void);
Function_Ptr Export_Function_Table[] =
{
0,
Print,
Read,
Write,
Process,
};
这是头文件:
export_table.h
#define ID_PRINT_FUNCTION 1
#define ID_READ_FUNCTION 2
#define ID_WRITE_FUNCTION 3
#define ID_PROCESS_FUNCTION 4
我正在寻找一种方案来根据命名常量在数组中的位置来定义它们,以便当函数的顺序发生变化时,常量也会发生变化。
(另外,我希望编译器或预处理器计算索引以避免打字等人为错误。)
In the embedded system I'm working on, we are using a table of function pointers to support proprietary Dynamic Libraries.
We have a header file that uses named constants (#define
) for the function pointer indices. These values are used in calculating the location in the table of the function's address.
Example:
(export_table.c)
// Assume each function in the table has an associated declaration
typedef void (*Function_Ptr)(void);
Function_Ptr Export_Function_Table[] =
{
0,
Print,
Read,
Write,
Process,
};
Here is the header file:
export_table.h
#define ID_PRINT_FUNCTION 1
#define ID_READ_FUNCTION 2
#define ID_WRITE_FUNCTION 3
#define ID_PROCESS_FUNCTION 4
I'm looking for a scheme to define the named constants in terms of their location in the array so that when the order of the functions changes, the constants will also change.
(Also, I would like the compiler or preprocessor to calculate the indices to avoid human mistakes like typeo's.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
使用 C99,您可以使用指定的初始值设定项:
(C99 中允许使用尾随逗号;从技术上讲,C90 中不允许使用尾随逗号。)
请注意,我故意重新排序 - 并且编译器将其排序。另外,虽然我将“#define”值重写为“enum”值,但它可以与任何一个一起使用。
请注意,据我所知,Windows 上的 MSVC 不支持此表示法。这意味着我无法在必须在 Linux 和 Windows 之间移植的代码中使用它——这让我很恼火。
Using C99, you can use designated initializers:
(The trailing comma is allowed in C99; technically, it is not in C90.)
Note that I deliberately reordered that - and the compiler sorts it out. Also, although I rewrote the '#define' values into 'enum' values, it would work with either.
Note that MSVC on Windows does not, AFAIK, support this notation. This means that I cannot use it in code that has to be ported between Linux and Windows - much to my exasperation.
请参阅这个答案< /a> 强制预处理器为您执行此操作的方法。
See this answer for a way to coerce the preprocessor in doing it for you.
您可以为每个函数指针定义一个包含命名元素的结构,而不是数组:
Instead of an array you can define a structure with named elements for each function pointer:
我的建议是:不要直接使用C。从以某种本地定义的 DSL 编写的输入文件生成 .c 和 .h 文件作为构建过程的一部分。然后,您只需维护一个源文件(用 DSL 编写),并且 DSL 编译器可确保导出的索引与数组的实现相匹配。
我们在这里采用了这种技术。 DSL 基本上是一个带注释的 C 文件,如下所示:
它将生成一个如下所示的
foo.h
和一个如下所示的
foo.c
:具有计算大括号嵌套和逗号的能力,以计算 C 数组中每个元素的索引。
My advice is: don't use C directly. Generate the .c and .h files from an input file written in some locally defined DSL as part of your build process. Then you only have a single source file to maintain (written in your DSL), and the DSL compiler ensures that the exported indices match the implementation of the array.
We employ this technique here. The DSL is basically an annotated C file that looks something like this:
which would generate a
foo.h
that looks like:and a
foo.c
that looks like:The parser has some ability to count brace nesting and commas to calculate the index of each element in the C array.
X 宏可以提供帮助。例如,创建一个新文件export_table_x.h,其中包含:
然后在export_table.h中使用:
在export_table.c中写入:
对原始功能的一项更改是ID_PRINT_FUNCTION现在是ID_Print_FUNCTION,等等
。文件很烦人,但是您可以通过使用 #ifdef 并将所有内容放入原始头文件中来避免这种情况,尽管这不太清楚。
X-macros could help. For example, create a new file export_table_x.h, containing:
Then in your export_table.h, use:
And in export_table.c, write:
One change to your original functionality is that ID_PRINT_FUNCTION is now ID_Print_FUNCTION, etc.
Having to add an extra file is annoying, but you could avoid this by using #ifdef's and putting everything in the original header file, although this is less clear.
很少有 C 程序员会利用
#undef
的强大功能,专门为您当前的目的重新定义宏。这使您可以在单个可读表中设置所有数据,并且可以在 1 个位置更新和修改该表。但是等等,还有更多 0 美元的超低价格以及免费的 S&H,您可以在 1 个地方完成所有函数头的繁琐操作。
现在,您可以将每个新函数添加到此标头顶部的一个位置,如果您想保留作为库的向后兼容性,最好添加到 FUNCTION_MAP 的末尾...否则您可以按字母顺序列出它们。
Few C programmers take advantage of the power of
#undef
, specifically redefining a macro for your current purposes. This allows you to set up all of your data in a single readable table that can be updated and modified in 1 place.but wait, there's more all for the low, low price of $0 with free S&H, you can do all of your function header mumbo jumbo all in 1 place.
Now you can just add each new function in one place at the top of this header, preferably to the end of FUNCTION_MAP if you want to preserve backward compatibility as a library... otherwise you can just list them alphabetically.