一个 C 程序,给定一个结构定义,生成一个函数来分配和初始化这个结构
A C program that ,given a structure definition, generates a function to allocate and initialise this structure
我在一本关于C数据结构的旧书上找到了这个练习,它给出了以下问题提示:
- Write a program that, given a structure definition, will generate a C function that allocates and initializes the structure (such a function is called a "constructor"). For example, given the input:
struct complex
{
double real;
double imaginarry;
}
function create_complex()
will be created having two arguments of type double
.
我试着想过如何创建这样一个程序,我唯一的解决办法是使用一个文件来获取结构输入并创建一个新的文本文件,我在其中编写函数。
还有其他方法可以解决这个问题吗?
我很感激。
如果您想从字面上将结构定义作为输入并输出一个函数定义,该函数定义 (1) 创建该类型的结构并且 (2) 具有与结构的每个元素对应的参数,那么您是正确:您需要将源代码作为文本文件阅读并手动解析定义。如果采用这种方法,我建议使用 lex and yacc 来生成生成代码的代码。像C这样的LR语法解析代码有很多陷阱
但是如果我们的目标是从一个定义中创建结构和函数,我们可以直接从源代码中使用X-Macros来实现。这些的诀窍是我们根据 function-like 宏定义我们的数据结构,例如#define X STRUCT(complex, ARG(double, real), ARG(double, imaginary))
但我们还没有定义这些宏 做什么 。然后我们包含一个特殊的头文件。
header定义宏,then包括X
(即文件中有文字X
;它包括,而不是#includes),根据宏定义展开。然后它重新定义宏来做一些不同的事情,并再次包含 X
,它又根据 new 宏定义进行扩展。因此,我们只需要指定一次定义(无需担心信息不同步),但我们会生成依赖它的所有不同代码段。
下面的例子展示了它是如何工作的;我们根据您的问题创建了 complex
结构,还创建了 struct other { int a; double b; }
以展示它如何处理多个类型定义。
struct_defn.h
#include <stdlib.h>
// Here, we expand X into a struct definition
#define STRUCT(NAME, ARGS) struct NAME { ARGS };
#define ARG(TYPE, NAME) TYPE NAME;
X
#undef ARG
#undef STRUCT
// Expand X into a function decl
#define STRUCT(NAME, ARGS) struct NAME *make_##NAME(struct NAME *out ARGS)
#define ARG(TYPE, NAME) , TYPE NAME
X
#undef ARG
#undef STRUCT
// Expand X into a function definition
#define STRUCT(NAME, ARGS) { \
if (!out) { \
out = malloc(sizeof(struct NAME)); \
if (!out) return NULL; \
} \
ARGS \
return out; \
}
#define ARG(TYPE, NAME) out->NAME = NAME;
X
#undef ARG
#undef STRUCT
#undef X
main.c
#include <stdio.h>
// We define each of the structures in terms of the X-Macros, then "call" the macro by including the file.
#define X STRUCT(complex, \
ARG(double, real) \
ARG(double, imaginary))
#include "struct_defn.X"
/* The above will expand to the following (but without the formatting)
*
* struct complex {
* double real;
* double imaginary;
* };
* struct complex *make_complex(struct complex *out, double real, double imaginary) {
* if (!out) {
* out = malloc(sizeof(struct complex));
* if (!out) return ((void *) 0);
* }
* out->real = real;
* out->imaginary = imaginary;
* return out;
* }
*
*/
#define X STRUCT(other, \
ARG(int, a) \
ARG(double, b))
#include "struct_defn.X"
int main() {
struct complex foo;
struct complex *bar = make_complex(NULL, 2.71828, 42.0);
make_complex(&foo, 3.14159265, 0.5);
struct other *baz = make_other(NULL, 4, 2);
printf("foo: %f, %f\nbar: %f, %f\nbaz: %d, %f\n",
foo.real, foo.imaginary,
bar->real, bar->imaginary,
baz->a, baz->b);
}
我在一本关于C数据结构的旧书上找到了这个练习,它给出了以下问题提示:
- Write a program that, given a structure definition, will generate a C function that allocates and initializes the structure (such a function is called a "constructor"). For example, given the input:
struct complex { double real; double imaginarry; }
function
create_complex()
will be created having two arguments of typedouble
.
我试着想过如何创建这样一个程序,我唯一的解决办法是使用一个文件来获取结构输入并创建一个新的文本文件,我在其中编写函数。
还有其他方法可以解决这个问题吗? 我很感激。
如果您想从字面上将结构定义作为输入并输出一个函数定义,该函数定义 (1) 创建该类型的结构并且 (2) 具有与结构的每个元素对应的参数,那么您是正确:您需要将源代码作为文本文件阅读并手动解析定义。如果采用这种方法,我建议使用 lex and yacc 来生成生成代码的代码。像C这样的LR语法解析代码有很多陷阱
但是如果我们的目标是从一个定义中创建结构和函数,我们可以直接从源代码中使用X-Macros来实现。这些的诀窍是我们根据 function-like 宏定义我们的数据结构,例如#define X STRUCT(complex, ARG(double, real), ARG(double, imaginary))
但我们还没有定义这些宏 做什么 。然后我们包含一个特殊的头文件。
header定义宏,then包括X
(即文件中有文字X
;它包括,而不是#includes),根据宏定义展开。然后它重新定义宏来做一些不同的事情,并再次包含 X
,它又根据 new 宏定义进行扩展。因此,我们只需要指定一次定义(无需担心信息不同步),但我们会生成依赖它的所有不同代码段。
下面的例子展示了它是如何工作的;我们根据您的问题创建了 complex
结构,还创建了 struct other { int a; double b; }
以展示它如何处理多个类型定义。
struct_defn.h
#include <stdlib.h>
// Here, we expand X into a struct definition
#define STRUCT(NAME, ARGS) struct NAME { ARGS };
#define ARG(TYPE, NAME) TYPE NAME;
X
#undef ARG
#undef STRUCT
// Expand X into a function decl
#define STRUCT(NAME, ARGS) struct NAME *make_##NAME(struct NAME *out ARGS)
#define ARG(TYPE, NAME) , TYPE NAME
X
#undef ARG
#undef STRUCT
// Expand X into a function definition
#define STRUCT(NAME, ARGS) { \
if (!out) { \
out = malloc(sizeof(struct NAME)); \
if (!out) return NULL; \
} \
ARGS \
return out; \
}
#define ARG(TYPE, NAME) out->NAME = NAME;
X
#undef ARG
#undef STRUCT
#undef X
main.c
#include <stdio.h>
// We define each of the structures in terms of the X-Macros, then "call" the macro by including the file.
#define X STRUCT(complex, \
ARG(double, real) \
ARG(double, imaginary))
#include "struct_defn.X"
/* The above will expand to the following (but without the formatting)
*
* struct complex {
* double real;
* double imaginary;
* };
* struct complex *make_complex(struct complex *out, double real, double imaginary) {
* if (!out) {
* out = malloc(sizeof(struct complex));
* if (!out) return ((void *) 0);
* }
* out->real = real;
* out->imaginary = imaginary;
* return out;
* }
*
*/
#define X STRUCT(other, \
ARG(int, a) \
ARG(double, b))
#include "struct_defn.X"
int main() {
struct complex foo;
struct complex *bar = make_complex(NULL, 2.71828, 42.0);
make_complex(&foo, 3.14159265, 0.5);
struct other *baz = make_other(NULL, 4, 2);
printf("foo: %f, %f\nbar: %f, %f\nbaz: %d, %f\n",
foo.real, foo.imaginary,
bar->real, bar->imaginary,
baz->a, baz->b);
}