Reversed byte order when reading data sequentially with input_byte

I’m trying to read bytes in order from an input channel. Using consecutive byte reads in an array initialization results in data stored in reverse order.

Example

type elf_bytes = { ident : int array; }                                                                                  
                                                                                                                         
let () =                                                                                                                 
  let ic = open_in_bin "/proc/self/exe" in
  let res = really_input_string ic 16 in
  String.iter (fun x -> Printf.printf "%d " (int_of_char x)) res;
  print_newline ();
  (* prints 127 69 76 70 2 1 1 0 0 0 0 0 0 0 0 0   <- expected *)
  seek_in ic 0;      
  let hdr = { ident =
    [| input_byte ic; input_byte ic; input_byte ic; input_byte ic;
       input_byte ic; input_byte ic; input_byte ic; input_byte ic;
       input_byte ic; input_byte ic; input_byte ic; input_byte ic;
       input_byte ic; input_byte ic; input_byte ic; input_byte ic |]
  } in
  Array.iter (fun x -> Printf.printf "%d " x) hdr.ident;
  print_newline ();
  (* prints 0 0 0 0 0 0 0 0 0 1 1 2 70 76 69 127     <- actual *)
$ hexdump /proc/self/exe | head -1
0000000 457f 464c 0102 0001 0000 0000 0000 0000
        ^  ^ ^  ^
        69 | 70 |
          127   76

Which would be the appropriate way for me to read (using the standard lib) bytes into these initialization array records?

Evaluation order is probably unspecified, as with constructor arguments:

# [|print_endline "1"; print_endline "2"|];;
2
1
- : unit array = [|(); ()|]

An easy option for this case is

Array.init 16 (fun _ -> input_byte ic)

In general you can fix evaluation order with let ... in ...as you’re already doing to construct hdr before iterating on it.

Thank you. I wasn’t aware of the fact that order is unspecified for this language construct. Assumed “imperative” evaluation order in the absence of laziness and such.

Indeed, evaluation order is unspecified. In practice, it is right-to-left everywhere (this is the order that is most natural for the implementation of currying), but it is better not to depend on this.

Cheers,
Nicolas

1 Like

It’s the case in bytecode, but I had the notion that in native code, it’s left-to-right. Isn’t it?

No, I don’t think so. More generally, evaluation order differences between byte- and native-code compilation should be considered a bug (see eg Evaluation order: ocamlopt difference on application of mutable field · Issue #13874 · ocaml/ocaml · GitHub and Ensure right-to-left evaluation of arguments in cmm_helpers by gretay-js · Pull Request #10732 · ocaml/ocaml · GitHub).

Cheers,
Nicolas

It was a misconception on my part then. Thanks!