如何自动生成C代码

5
我正在处理一个C语言项目。我发现根据某些规则可以自动生成大量代码。例如,如果我只是指定一些C结构体,那么就可以基于它们自动生成代码。我知道这是可行的,但我以前没有尝试过。有经验的C程序员能否提供一些指导或分享如何在最小工程投入下完成此类工作的经验?
编辑:具体而言,我是否需要编写一个自定义C解析器来完成所有这些操作,还是有更简单的方法来处理这个问题?

您正在寻找支持模板的集成开发环境(IDE)。 - karlphillip
4
此问题表述不清。您到底想要生成什么代码?为什么不能编写一个输出文本的程序呢?毕竟,这就是 C 代码所做的一切。 - paddy
2
一些指针... - P.P
8
招聘一名实习生... - Kerrek SB
1
如果我只指定C结构,那么代码可以自动生成。问题是,代码要做什么?只是定义“struct”类型吗?您还想要生成为这些类型分配/释放内存的代码吗?操作和访问成员?格式化显示? - John Bode
显示剩余2条评论
3个回答

3
易于处理的是1:1语法替换。
难点在于超出1:1语法替换的有意义操作。
如果您过度依赖宏,您会遇到(虚构的名称)认知漂移问题,在这种情况下,您正在设计自己的语言(宏语言),但编译器和运行程序使用的是另一种语言。简单的映射不会使新语言更加繁琐,但由于宏仅在纯文本级别上运行,即使是简单的映射也会变得非常复杂。
如果您使用C ++,那么一个更好的解决方案是使用模板。 模板提供了许多与宏相同的功能,但是它们不会遭受太多认知漂移的困扰,因为模板是具备类型系统意识的替换。
随着类似C的语言结构的语法和含义的发展,您会发现新的语言经常试图“修复”通过纯C解决所需的重复代码量的问题。尝试学习一些“接近”C的新语言,你会对减少这种代码重复的方式有更好的理解,从而在C中做出更好的“生成”选择。

2

我见过的一种有效方法是使用宏(通常被人所厌恶的工具)。宏有两个特点可以帮助使生活变得更加容易,单个井号‘#’可以将参数转换为字符串,例如#_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 

那么,在需要声明或实现应处理结构的地方,可以以不同方式定义宏。例如:

#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


2

在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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接