Macos 使用CTypes和Foreign将字符串从C库返回到OCaml

Macos 使用CTypes和Foreign将字符串从C库返回到OCaml,macos,ocaml,ffi,Macos,Ocaml,Ffi,我在从OCaml映射本机OSX调用时遇到了一些问题,c调用需要传入缓冲区和大小。我已经在现实世界的OCaml中使用了CTypes和Foreign的例子,但它们没有涵盖这个案例,或者至少我不清楚如何使用它 以下是我的OCaml片段: open Core.Std open Unix open Ctypes open Foreign (* from /usr/include/libproc.h int proc_pidpath(int pid, void * buffer, uint32_t

我在从OCaml映射本机OSX调用时遇到了一些问题,c调用需要传入缓冲区和大小。我已经在现实世界的OCaml中使用了CTypes和Foreign的例子,但它们没有涵盖这个案例,或者至少我不清楚如何使用它

以下是我的OCaml片段:

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()
,是否有更好的方法包装此调用,使其返回选项类型(String或Nil)或仅返回一个字符串?

此问题与此有许多共同的问题。我鼓励你看一看

对于您的特定问题,以下方法应该有效(它不使用
Core
,因此您可能需要调整一些内容,它们是否将
Unix.getpid
的结果抽象化了?)


很好用,谢谢。我想我遇到了麻烦,因为我在寻找一个
外来的
声明,它完成了整个事情,而不是自己做了一些事情。是否有一种惯用的OCaml方法将Unix.Unix_错误编码到方法签名中?将其包装在选项中是否合理?对于一个无例外的设计,我建议使用以下签名:
val pidpath:int->[`Ok of string | `Error of Unix.Error]
(两个反勾应该是一个反勾号)如果您在让这个示例工作时遇到问题,请记住上面的数组引用的是Ctypes中的模块,最近更名为卡雷。
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 *))