0

I want to use Emacs to quickly convert hex to decimal.

If I type M-: #x1234 (i.e. 0x12 0x34), I get 4460 which (I think) means Emacs is interpreting it as big endian.

How might I convert hex to decimal as little endian, so that #1234 is interpreted as 13330?

Lorem Ipsum
  • 4,327
  • 2
  • 14
  • 35
  • The input `#x0001` has no relationship to the [endianness](https://en.wikipedia.org/wiki/Endianness) of byte sequences. The leading zeros are just ignored. – Tobias Jul 05 '19 at 16:35
  • I have no doubt I'm confusing myself. It seems like endianness does matter. If I consider `#1234` (i.e. `0x12 0x34`), Emacs returns `4460` which corresponds to big endian. Little endian would be `13330`. – Lorem Ipsum Jul 05 '19 at 16:45
  • 3
    `#x1234` is just the hexadecimal number. It is not considered as sequence of bytes. – Tobias Jul 05 '19 at 17:08

1 Answers1

2

#x1234 is just a hex number and not a byte-encoding. You can easily define a byte encoding yourself. For an instance with the following my-byte-decode function:

(defun my-byte-decode (list)
  "Decode hex number big-endian encoded as sequence of bytes in a list."
  (cl-reduce (lambda (hi lo) (+ (* #x100 hi) lo)) list))

You can decode a little endian encoded number (#x34 #x12) by (my-byte-decode (nreverse '(#x34 #x12))).

For completeness the encoding function:

(defun my-byte-encode (number)
  "Big-endian encode hex NUMBER.
See `my-byte-decode' for details on the encoding."
  (unless (integerp number)
    (user-error "Expected an integer"))
  (let (ret)
    (while (/= number 0)
      (setq ret (cons (mod number #x100) ret))
      (setq number (/ number #x100)))
    (or ret (list 0))))

Test: (equal (my-byte-encode #x1234) '(#x12 #x34)) gives t.

You get little-ending encoding by wrapping the my-byte-encode into a nreverse: (equal (nreverse (my-byte-encode #x1234)) '(#x34 #x12)) gives t.


Now I address the new version of your question:

How might I convert hex to decimal as little endian, so that #1234 is interpreted as 13330?

EDIT: We already discussed in the comments that the number #x0001 is the same as 1. so the word size encoded in the string #x0001 through the leading zeros is inevitably lost when the Elisp interpreter reads the string and interprets it as a number.

If you know the word size in advance you can pad the read byte sequence with zeros:

(defun my-fill-front (list size val)
  "If LIST is shorter than SIZE fill it at front.
Use a list with VAL for fitting the size."
  (let ((len (length list)))
    (if (< len size)
    (append (make-list (- size len) val)
        list)
      list)))

Now you have all the tools above. Just use the encoding function, pad it with zeros such that it has the right size, transform to little endian, and decode:

(my-byte-decode (nreverse (my-fill-front (my-byte-encode #x1234) 2 0)))

The answer is 13330 as you wish.

Tobias
  • 32,569
  • 1
  • 34
  • 75
  • There isn't enough information to do an endianness conversion. You don't know how many zeros to add to the left of the input. An endianness converter should take a basis size (you've hard-coded it to 256, ok, why not) and a number of digits (here you're assuming that the size is whatever causes the input not to have zeros on the left). – Gilles 'SO- stop being evil' Jul 06 '19 at 09:39
  • @Gilles I am aware of that one needs to know the word size. And I already tried to convince the OP about that. The OP changed the number in his question from `#x0001` to `#x1234` because of that. But, you are right, I should clarify the restrictions in the answer. Using bytes for the definition of endianness is [pretty much standard](https://en.wikipedia.org/wiki/Endianness). I do not only take that from the wiki page but also from my own experience. I already had to fight issues with the endianness on work and encountered always byte encoded systems. – Tobias Jul 06 '19 at 14:35
  • @Gilles I added a function for padding the generated list at the front to obtain the right word size. That should solve the problem. – Tobias Jul 06 '19 at 15:06