The conversion INT has an unsigned counterpart UINT but there is no corresponding unsigned version of LONG. In order to use LONG to pass unsigned values, it is necessary to adjust the value on the SML side (which is an int) so that the range checking of LONG does not reject valid values. For example, see my definition of ULONG below.

However, I can't see way to define ULONG portably - the SML side adjustment needs to know the size of an unsigned long. Is this available somewhere? Is there some clever way to define a portable ULONG in terms of LONG?

Phil


local
  val m =
    case PolyML.architecture () of
      "X86_64" => IntInf.pow (2, 64)
    | "I386"   => IntInf.pow (2, 32)
    | _        => raise Fail "unknown architecture"

  val half_m = m div 2

  fun fromLong x =
    (* Assume x in range of (signed) long int. *)
    if x < 0
    then x + m
    else x

  fun toLong x =
    (*
     * Ensure result outside range of (signed) long int if and only
     * if x is outside the range of unsigned long int by swapping
     * regions [~m/2, 0) and [m/2, m).
     *)
    if half_m <= x andalso x < m
    then x - m
    else if ~ half_m <= x andalso x < 0
    then x + m
    else x
in
  val ULONG =
    CInterface.mapConversion (fromLong, toLong) CInterface.LONG
end


(* Test ULONG *)

local
  open CInterface
in
  fun printULong n =
    call2
      (get_sym "libc.so.6" "printf")
      (STRING, ULONG)
      VOID
      ("n = %lX\n", n)
end


val pow_2_32 = IntInf.pow (2, 32);
val pow_2_64 = IntInf.pow (2, 64);

printULong ~1;              (* should fail *)
printULong 0;               (* always ok *)

printULong (pow_2_32 - 1);  (* always ok *)
printULong pow_2_32;        (* should fail when long is 32 bits *)

printULong (pow_2_64 - 1);  (* ok when long is at least 64 bits *)
printULong pow_2_64;        (* should fail when long is 64 bits *)

_______________________________________________
polyml mailing list
polyml@inf.ed.ac.uk
http://lists.inf.ed.ac.uk/mailman/listinfo/polyml

Reply via email to