0

I have an uint64 (what would be an unsigned long long in C) which I want to convert in an array of bytes.

This is how I'm doing it right now (in Nim code):

  • Value is typedef'd as unsigned long long
  • Byte is typedef'd as unsigned char
  • CD is an array of Bytes
        proc writeValue(v:Value) =
            CD.add(Byte(v shr 56))
            CD.add(Byte(v and Value(0x00ff000000000000)))
            CD.add(Byte(v and Value(0x0000ff0000000000)))
            CD.add(Byte(v and Value(0x000000ff00000000)))
            CD.add(Byte(v and Value(0x00000000ff000000)))
            CD.add(Byte(v and Value(0x0000000000ff0000)))
            CD.add(Byte(v and Value(0x000000000000ff00)))
            CD.add(Byte(v and Value(0x00000000000000ff)))

And this is how I'm reading it back (get an uint64 starting from a specific position in the array: IP)

template readValue():Value =
    inc(IP,8); (Value(CD[IP-8]) shl 56) or (Value(CD[IP-7]) shl 48) or (Value(CD[IP-6]) shl 40) or (Value(CD[IP-5]) shl 32) or (Value(CD[IP-4]) shl 24) or (Value(CD[IP-3]) shl 16) or (Value(CD[IP-2]) shl 8) or Value(CD[IP-1])


Is there a more efficient way? Am I wasting performance the way I'm doing it?

Tom Tanner
  • 9,244
  • 3
  • 33
  • 61
Dr.Kameleon
  • 22,532
  • 20
  • 115
  • 223
  • 4
    This is not [tag:c].. – LPs Dec 19 '19 at 08:38
  • In C it's easy, since it allows type-punning using unions. – Some programmer dude Dec 19 '19 at 08:40
  • @LPs Well, the code above is not C - it's Nim. But, first Nim and C are pretty much intertwined (Nim produces C code), and second, what I need is not a language-specific solution. – Dr.Kameleon Dec 19 '19 at 08:41
  • Anyways, given that I got my "C" tag removed and that most of you probably do not know how Nim works... I can use pure C code as well. It really doesn't matter. In Nim, the two can be mixed. I just need to see if there's any fault in my logic... – Dr.Kameleon Dec 19 '19 at 08:46
  • You are asking for performances and this is closely related to the implementation language. Even more so in case of a language that produce, as output, another langue source code (double indirection). – LPs Dec 19 '19 at 08:56
  • For example, using [tag:c], you can use `union` to directly access bytes... – LPs Dec 19 '19 at 08:58

1 Answers1

1

There is an more efficient way. I am not sure if it is safe and it does not depend on a particular machine and/or architecture.

Anyway. You can do it using cast: https://nim-lang.org/docs/manual.html#statements-and-expressions-type-casts

type Value = uint64
type Byte = uint8
type ValueBytes = array[0..7, Byte]

proc toBytes(v: Value): ValueBytes =
  result = cast[ValueBytes](v)

proc toValue(bytes: ValueBytes): Value =
  result = cast[Value](bytes)

proc toBytesManual(v: Value): ValueBytes =
  result[0] = Byte((v shr 0) and Value(0xff))
  result[1] = Byte((v shr 8) and Value(0xff))
  result[2] = Byte((v shr 16) and Value(0xff))
  result[3] = Byte((v shr 24) and Value(0xff))
  result[4] = Byte((v shr 32) and Value(0xff))
  result[5] = Byte((v shr 40) and Value(0xff))
  result[6] = Byte((v shr 48) and Value(0xff))
  result[7] = Byte((v shr 56) and Value(0xff))

proc toValueManual(bytes: ValueBytes): Value =
  result += Value(bytes[0]) shl 0
  result += Value(bytes[1]) shl 8
  result += Value(bytes[2]) shl 16
  result += Value(bytes[3]) shl 24
  result += Value(bytes[4]) shl 32
  result += Value(bytes[5]) shl 40
  result += Value(bytes[6]) shl 48
  result += Value(bytes[7]) shl 56

let value = 123456789'u64
let bytes = [21'u8, 205'u8, 91'u8, 7'u8, 0'u8, 0'u8, 0'u8, 0'u8]

assert toBytes(value) == bytes
assert toBytesManual(value) == toBytes(value)
assert toValue(bytes) == value
assert toValue(bytes) == toValueManual(bytes)
petraszd
  • 4,249
  • 1
  • 20
  • 12