gpt4 book ai didi

c - 如何从 C 程序中的外部文件加载 mruby 代码?

转载 作者:太空宇宙 更新时间:2023-11-03 23:29:24 25 4
gpt4 key购买 nike

我开始使用 mruby .我对 C 编程也很陌生,所以我可能不熟悉许多基础知识。我能够 compile the example mruby program从字符串加载 ruby​​ 代码。现在我想从外部文件加载它。这是我正在使用的示例代码:

#include <stdlib.h>
#include <stdio.h>
#include <mruby.h>

static mrb_value my_c_method(mrb_state *mrb, mrb_value value)
{
puts("Called my C method");
return value;
}

int main(void)
{
mrb_state *mrb = mrb_open();

struct RClass *mymodule = mrb_define_module(mrb, "MyModule");
mrb_define_class_method(mrb, mymodule, "my_c_method", my_c_method, MRB_ARGS_NONE());

mrb_load_string(mrb, "MyModule.my_c_method"); // move this to an external file
return 0;
}

如您在上面的示例中所见,我想将 ruby​​ 代码移动到外部文件。对于是否可以简单地“包含”ruby 文件,或者是否需要将其预编译为 .mrb 文件,我感到有些困惑。即使那样,我也不确定如何在编译时包含该 .mrb 文件。

我需要更改什么才能从外部文件加载 ruby​​ 代码?

最佳答案

假设您的代码存储在文件 foo 中,您只需打开文件并读取它。要打开文件,您需要在 stdio.h 中定义的 fopen()。然后,您可以使用 fgets() 逐行读取它。我不熟悉 mruby,所以我不确定 mrb_load_string 是否期望每个 mruby 代码都在一行中。我会这么认为。方法如下:

#define MAX_CODE_SIZE 128
FILE *code;
char code_buf[128]
code = fopen("foo", "r");
if (code == NULL) {
/* File couldn't be opened, handle error case... */
}
fgets(code_buf, MAX_CODE_SIZE, code);
/* Do some work ... */

fclose(code); /* Don't forget to close the file */

这段代码读取文件 foo 的第一行,最多 127 个字符(包括换行符),并将其存储在 code_buf 中。然后您可以调用 mrb_load_string:

mrb_load_string(mrb, code);

我不确定这是否是您想要的,我从未接触过 mruby,但据我所见,mrb_load_string 需要包含代码的 char *,并且你希望它来自一个文件。这就是您的做法。

如果你想读取一个包含多行代码的文件,你别无选择,只能分配一个足够大的缓冲区并使用fread()读取它:

#include <stdio.h>
#define MAX_LINE_LENGTH 128
#define MAX_LINES 256
#define MAX_FILE_SIZE MAX_LINE_LENGTH*MAX_LINES

char code[MAX_FILE_SIZE];

int read_code(char *filepath) {
FILE *fp = fopen(filepath, "r");
if (fp == NULL)
return 0;
fread(code, 1, MAX_FILE_SIZE, fp);
fclose(fp);
return 1;
}

这个函数读取整个文件(假设它没有超过我们的缓冲区限制)。 code 是全局的,因为如果分配较大的局部变量(另一种选择是使用动态分配),您很容易达到堆栈容量。当您调用 read_code() 时,您应该确保检查它的返回值,以检查打开文件时可能出现的错误。此外,您可以使用 fread() 的返回值来了解缓冲区大小是否不足以读取所有内容。

请确保您在完成后不要忘记关闭文件。

编辑:对于 fgets() 版本,请注意,如果该行少于 128 个字符,换行符将保留在 code_buf。如果是这种情况,您可能希望将 code_buf[strlen(code_buf)-1] 设置为 '\0'

更新:

根据我们对下面评论的讨论,我正在用一个基本的解析器更新我的答案,以使您能够在编译时读取 ruby​​ 文件。基本上,解析器将读取您的 ruby​​ 文件并生成一个输出文件,其中包含将文件内容插入 char 数组的有效 C 代码。相应地转义特殊字符。在这里:

#include <stdio.h>

void inline insert(int, FILE *);

int main(int argc, char *argv[]) {
FILE *out, *in;
int c;
if (argc != 3) {
printf("Usage: %s <input_file> <output_file>\n", argv[0]);
return 1;
}

in = fopen(argv[1], "r");
out = fopen(argv[2], "w");

if (out == NULL) {
printf("Unable to create or write to %s\n", argv[1]);
return 1;
}

if (in == NULL) {
printf("Unable to read %s\n", argv[1]);
return 1;
}

fputs("#ifndef MRUBY_CODE_FILE_GUARD\n", out);
fputs("#define MRUBY_CODE_FILE_GUARD\n", out);
fputs("char mruby_code[] = \"", out);
while ((c = getc(in)) != EOF)
insert(c, out);
fputs("\";\n", out);
fputs("#endif\n", out);
fclose(in);
fclose(out);
return 0;
}

void inline insert(int c, FILE *fp) {
switch (c) {
case '\a':
fputs("\\a", fp);
break;
case '\b':
fputs("\\b", fp);
break;
case '\f':
fputs("\\f", fp);
break;
case '\n':
fputs("\\n", fp);
break;
case '\r':
fputs("\\r", fp);
break;
case '\t':
fputs("\\t", fp);
break;
case '\v':
fputs("\\v", fp);
break;
case '\\':
fputs("\\\\", fp);
break;
case '\'':
fputs("\\'", fp);
break;
case '"':
fputs("\\\"", fp);
break;
default:
fputc(c, fp);
}
}

现在,回到您的原始程序并在开头添加以下 include 指令:

#include mruby_code.h

你必须执行以下步骤来编译一个可运行的程序,假设这个解析器被编译成一个名为 fileparser.c 的文件:

  • 运行 ./fileparser/path/to/mruby_code_file/path/to/program/mruby_code.h
  • 编译您的原始程序(它将包含 mruby_code.h)

mruby 代码在名为mruby_code 的变量中提供。这是一个字符数组,因此您可以将它传递给 mrb_load_string。瞧,你在编译时读取了 mruby 文件一次

关于c - 如何从 C 程序中的外部文件加载 mruby 代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19347984/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com