我正在做一个 C 项目。我观察到很多代码可以根据某些规则自动生成。IE。如果我只指定 C 结构,基于此,可以自动生成代码。我知道它可以做到,但我以前没有做过。如果有经验的 C 程序员可以给出某些指示或分享他们如何以最少的工程工作量做这些事情的经验,那就太好了。
编辑:要非常具体,我是否需要在 C 中编写一个自定义解析器来完成所有这些工作,还是有一些更简单的方法来处理这个问题?
我正在做一个 C 项目。我观察到很多代码可以根据某些规则自动生成。IE。如果我只指定 C 结构,基于此,可以自动生成代码。我知道它可以做到,但我以前没有做过。如果有经验的 C 程序员可以给出某些指示或分享他们如何以最少的工程工作量做这些事情的经验,那就太好了。
编辑:要非常具体,我是否需要在 C 中编写一个自定义解析器来完成所有这些工作,还是有一些更简单的方法来处理这个问题?
简单的部分与 1:1 语法替换有关。
困难的部分是做任何超出 1:1 语法替换的非常有意义的事情。
如果你过分依赖宏,你会遇到认知漂移的(编造名称)问题,你现在正在设计自己的语言(宏语言),但编译器和运行程序正在使用另一种语言。简单的映射不会使新语言变得更麻烦,但由于宏在纯文本替换级别上运行,即使是简单的映射也会很快变得复杂。
如果您使用的是 C++,那么更好的解决方案是使用templates。模板提供了许多与宏相同的功能,只是它们不会受到太多认知漂移的影响,因为模板可以替代对类型系统的认识。
随着类 C 语言结构的语法和含义的发展,您会发现较新的语言经常尝试“修复”纯 C 解决方案所需的重复代码量问题。尝试学习一些“接近”C 的新语言,您将了解可以减少这种代码重复的方法,从而在 C 的“生成”工作中做出更好的选择。
在 C 中进行元编程的一种相对传统的方法是使用X 宏之类的技术。
本质上,不是使用普通的 C 结构声明,而是完全使用宏定义结构,就像这样
BEGIN_STRUCT(pointf)
FIELD(float, x)
FIELD(float, y)
END_STRUCT(pointf)
并将这些定义放在一个头文件中,不防止多重包含。
然后,对于您需要生成的每一段代码(包括基本结构)、#define
每个元语言宏、#include
定义头和#undef
元语言宏:
#define BEGIN_STRUCT(N) struct N {
#define FIELD(T,N) T N;
#define END_STRUCT(N) }
#include "definitions.h"
#undef BEGIN_STRUCT
#undef FIELD
#undef END_STRUCT
我见过的一种有效方法是使用宏(一种经常被讨厌的工具)。宏有两个特性可以让生活变得更轻松,单哈希“#”可以将参数转换为字符串,#_name
即将被翻译成字符串,"fieldName1"
双哈希“##”将参数与其他东西连接起来,这反过来可以扩展新事物,STRUCT_##_type##_str
即将被翻译成STRUCT_int_str
哪个将被翻译成"%d"
首先将宏中的结构或“描述”包装到自己的文件中(the-struct.def)
STRUCT_BEGIN(s_my_struct)
STRUCT_FIELD(int, fieldName1)
STRUCT_FIELD(int, fieldName2)
STRUCT_FIELD(int, fieldName3)
STRUCT_END(s_my_struct)
// Note that you can add more structs here and all will automatically get defined and get the print function implemented
然后可以在想要声明或实现应该处理结构的东西的地方以不同的方式定义宏。IE
#define STRUCT_BEGIN(_name) struct _name {
#define STRUCT_END(_name) };
#define STRUCT_FIELD(_type, _name) _type _name;
#include "the-struct.def"
// then undef them
#undef STRUCT_BEGIN
#undef STRUCT_END
#undef STRUCT_FIELD
并制作一个打印结构的函数
#define STRUCT_BEGIN(_name) void print_ ## _name(struct _name *s) {
#define STRUCT_END(_name) }
#define STRUCT_FIELD(_type, _name) printf("%s = " STRUCT_##_type##_str "\n", #_name, s->_name);
#define STRUCT_int_str "%d" /* this is to output an int */
// add more types...
#include "the-struct.def"
// then undef them
#undef STRUCT_BEGIN
#undef STRUCT_END
#undef STRUCT_FIELD
#undef STRUCT_int_str
其他用途可以是自动生成函数以交换字节等。
在这里做了一个小例子作为要点https://gist.github.com/3786323