【问题标题】:Returning a string from a C library to OCaml using CTypes and Foreign使用 CTypes 和 Foreign 将字符串从 C 库返回到 OCaml
【发布时间】:2014-03-26 05:03:12
【问题描述】:

我在映射来自 OCaml 的本机 OSX 调用时遇到了一些问题,其中 c 调用需要传入缓冲区和大小。我已经研究了 Real World OCaml 中关于使用 CTypes 和 Foreign 的示例,但它们没有报道这个案子,或者至少我不清楚我会怎么做。

这是我的 OCaml 的 sn-p:

open Core.Std
open Unix
open Ctypes
open Foreign

(* from /usr/include/libproc.h
  int proc_pidpath(int pid, void * buffer, uint32_t  buffersize);
*)
let proc_pidpath = foreign "proc_pidpath" (int @-> ptr void @-> int @-> returning int)

let () =
  let pid = Pid.to_int (Unix.getpid ()) in
  let buf = allocate string 255 in
  let path = proc_pidpath(pid, buf, 255) in
  printf "Pid: %i Path: %s\n" pid buf

如何分配缓冲区以传递给proc_pidpath(),是否有更好的包装此调用的方法,使其返回选项类型(字符串或零)或仅返回字符串?

【问题讨论】:

    标签: macos ocaml ffi


    【解决方案1】:

    这个问题与one 有很多共同点。我鼓励你看看它。

    对于您的特定问题,以下应该可以工作(它不使用Core,因此您可能需要调整一些东西,它们是否使Unix.getpid 的结果抽象?)。

    open Ctypes;;
    open Foreign;;
    
    module Proc : sig
      val pidpath : int -> string 
      (** @raise [Unix.Unix_error] in case of error *)
    end = struct
    
      let pidpathinfo_maxsize = 1024 * 4 
      (* value of PROC_PIDPATHINFO_MAXSIZE. 
         N.B. this should not be hardcoded, see 1) in this answer 
         https://stackoverflow.com/questions/20851390 *)
    
      let char_array_as_string a len =    
      (* This function should soon no longer be required see:
         https://github.com/ocamllabs/ocaml-ctypes/pull/139 *)
        let b = Buffer.create len in 
        for i = 0 to len -1 do Buffer.add_char b (Array.get a i) done;
        Buffer.contents b
    
      let pidpath = 
        foreign ~check_errno:true "proc_pidpath"
          (int @-> ptr char @-> int @-> returning int)
    
      let pidpath pid =
        let path = Array.make char ~initial:'\x00' pidpathinfo_maxsize in 
        let len = pidpath pid (Array.start path) pidpathinfo_maxsize in
        char_array_as_string path len
    end
    
    let () =
      let print_pidpath pid = 
        try
          let path = Proc.pidpath pid in 
          Format.printf "Pid %d: %s@." pid path; 
        with Unix.Unix_error (e, _, _) -> 
          Format.eprintf "Pid %d: %s@." pid (Unix.error_message e)
      in
      print_pidpath (Unix.getpid ()); 
      print_pidpath (-10000 (* bogus *))
    

    【讨论】:

    • 效果很好,谢谢。我想我遇到了麻烦,因为我正在寻找一个 foreign 声明来完成整个事情,而不是自己做一些管道。是否有一种惯用的 OCaml 方法将 Unix.Unix_error 编码到方法签名中?将其包装在 Option 中是否明智?
    • 对于一个例外的设计,我建议这个签名:val pidpath : int -> [ ``Ok of string | ``Error of Unix.error ](两个反引号应该是一个)
    • 如果您在让这个示例运行时遇到问题,请记住,上面的 Array 指的是 Ctypes 中的模块,该模块最近已重命名为 CArray。
    猜你喜欢
    • 1970-01-01
    • 2017-06-05
    • 2018-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-10
    相关资源
    最近更新 更多