从OCaml获取C二进制数据

Gai*_*ius 5 c ocaml ffi binary-data

(为了论证而忽略字节序 - 这只是一个测试用例/概念证明 - 我也绝不会strcpy在实际代码中使用!)

考虑以下简单的C代码:

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

/* variables of type message_t will be stored contiguously in memory */
typedef struct {
  int message_id;
  char message_text[80];
} message_t;

int main(int argc, char**argv) {
  message_t* m = (message_t*)malloc(sizeof(message_t));
  m->message_id = 1;
  strcpy(m->message_text,"the rain in spain falls mainly on the plain");

  /* write the memory to disk */
  FILE* fp = fopen("data.dat", "wb");
  fwrite((void*)m, sizeof(int) + strlen(m->message_text) + 1, 1, fp);
  fclose(fp);

  exit(EXIT_SUCCESS);
}
Run Code Online (Sandbox Code Playgroud)

它写的文件很容易从磁盘中读回:

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

typedef struct {
  int message_id;
  char message_text[80];
} message_t;

int main(int argc, char**argv) {
  message_t* m = (message_t*)malloc(sizeof(message_t));

  FILE* fp = fopen("data.dat", "rb");
  fread((void*)m, sizeof(message_t), 1, fp);
  fclose(fp);

  /* block of memory has structure "overlaid" onto it */
  printf("message_id=%d, message_text='%s'\n", m->message_id, m->message_text);

  exit(EXIT_SUCCESS);
}
Run Code Online (Sandbox Code Playgroud)

例如

$ ./write 
$ ./read 
message_id=1, message_text='the rain in spain falls mainly on the plain'
Run Code Online (Sandbox Code Playgroud)

我的问题是,在OCaml中,如果我只有:

type message_t = {message_id:int; message_text:string}
Run Code Online (Sandbox Code Playgroud)

我如何获得该数据?Marshal做不到,也做不到input_binary_int.我可以调用C中的辅助函数,比如"是什么sizeof(int)"然后获取n个字节并调用C函数"将这些字节转换为int",例如但在这种情况下我不能添加任何新的C代码,"解包"必须在OCaml中完成,基于我所知道的"应该".它只是在sizeofs 块中迭代字符串或寻找'\ 0'还是有巧妙的方法?谢谢!

The*_*ema 6

为了做这种低级结构处理,我发现OCaml Bitstring 非常方便.如果您将所有80个字符写入磁盘,则message_t的等效阅读器将是这样的:

bitmatch (Bitstring.bitstring_from_file "data.dat") with
  | { message_id : 32;
      message_text : 8 * 80 : string;
    } -> 
      Printf.printf "message_id=%ld, message_text='%s'\n" 
                    message_id message_text
  | { _ } -> failwith "Not a valid message_t"
Run Code Online (Sandbox Code Playgroud)

原样,你必须修剪message_text,但也许bitstring是你想要做的一般任务.


Gai*_*ius 1

谢谢大家的建议;我已经在我的博客中写下了我决定采用的方法。