#Array to Int (and other combinations)

1 messages · Page 1 of 1 (latest)

plain goblet
#

I'm having a little trouble with converting arrays (i.e []u8, []int, etc.) into an int, in this case. I primarily come from a C#/Java and Some C/C++ background, so those languages had a lot of helper functions. I attempted to produce it manually by doing:
for i := len(array) - 1; i >= 0; i -= 1 {
val := val * 10 + array[i];
}
as well as the vice-versa:
for i := 0; i < len(array); i += 1 {
val := val * 10 + array[i];
}
but none of those produce what I'm looking for. For example, I have an array that has { 0x00, 0x1A, 0xFA, 0x00 } and I want to convert it to 0x001AFA00 or the reverse 0x00FA1A00, but instead I get results such as 0x00CBFC00 and so on.

Normally in C# or Java you would just use BitConverter.ToInt32(val) and when looking at the underlining code it's similar to this, so I'm not sure where I'm going wrong. I did look up some C99 examples and they're relatively similar, adding usage of sscanf or malloc.

calm axle
#

your math is wrong

#

you are looking for bit shifting not multiplication

#

if you have an array type, you can transmute it to an integer if they match in size ([4]byte to i32)

calm axle
frosty viper
#

You want to use bitshifts yes

#

But you might also be able to get away with just casting pointers

#

And just reading the 4 bytes as an i32 directly via the pointer

#

Pointer casting for example is what C# does

plain goblet
#

Using @calm axle suggestion I did use 16 and then proceeded to go all the way to 256 where 256 did the trick, but that doesn't seem right as far as I know. I did manage to find the C# BitConverter class reference and it shows the usage of bitshift, but for some odd reason doing val_ptr := &array[0] and then val_ptr + 1 gives an error, which is how the underlining code in C# does it.

#

return (*pbyte) | (*(pbyte + 1) << 8) | (*(pbyte + 2) << 16) | (*(pbyte + 3) << 24);

#

more specifically

frosty viper
#

Just use an indexer for pbyte

#

Much easier

calm axle
frosty viper
#

You can't do math on typed pointers in general iirc no?

#

You have to use a rawptr or index multipointers

calm axle
#

you can do some obscurity and do whatever_ptr_type(uintptr(val_ptr) + 1))

calm axle
calm axle
frosty viper
#

I'm also not sure where you found the reference for BitConverter as it doesn't line up with what I found

#

Ah right

#

Either way doing pbyte[1] should work instead of the +1 into the dereference

plain goblet
#

Hm. Okay, thank you. I'll give it another go to see what works best.

plain goblet
#

I suppose it's a matter of opinion, but since I'm not well verse in bitshifts I'd rather ask. I managed to get the results I was looking for using this:
for i := 0; i < len(array); i += 1 { val = (val << 8) | cast(u32)array[i]; }

#

Does that seem correct?

calm axle
#

why 8

plain goblet
#

I'll be honest, I don't know I was messing with numbers and that's what ended up working.

calm axle
#

does it work tho?

#

what is the size of the val

plain goblet
#

Seems to be working. All the values for that array are { 0x50, 0x4B, 0x47, 0x34 }, so I'm assuming since they're 8 byte values it's the reason it works?

#

so from there val turns into 0x50 or 80, then 0x4B and so on

frosty viper
#

It's 8 because that's the amount of bits in a byte

#

So you shift a byte to the side

plain goblet
#

Ah. I was looking for bitshift explanations and one post stated this So 6 << 1 is equivalent to 6 * 2, and 6 << 3 is equivalent to 6 * 8. A good optimizing compiler will replace multiplications with shifts when possible. so it more or less threw me off. since I took what it said and then just started added +1 to every number I tried till I got to 8.

#

Now I know tho, thanks for the guidance!

frosty viper
#

The post just essentially says that shifting is the same as multiplying by a power of two

#

That's also why the 4 byte long i32 is called an i32

#

4 * 8

plain goblet
#

Oh okay, thank you for the clarification, that makes a lot more sense now.

wild mantle
#

FYI, what you did is essentially equivalent to value := cast(u32) cast(^u32le)(raw_data(array[0:4]))^.
(Or cast(^u32be) if the bytes are the other way around.)

#

This is:

  • Get a slice of the first 4 bytes.
  • Get the slice's pointer.
  • Assume that pointer is actually a pointer to a little-endian u32.
  • Get me a value-copy of those bytes as a little-endian u32.
  • Convert it to native endianness. (A no-op on LE machines.)
#

The order of the shifts in the original version are doing the same job as the LE/BE stuff in this example.

#

You can alternatively do cast(^u32le)&array[0], but this doesn't do any bounds checks, and you actually do mind if there's not 4 bytes; hence the use of a slice to make sure it panics if there's not.

#

To go the other way, you could also use transmute to convert between an array of bytes and an integer.

val := u32(47)
bytes := transmute([4]byte) u32le(val)
copy(array[0:4], bytes[:])
#

transmute is doing the same thing as the cast(T)(ptr)^ thing in the original example, but it doesn't semantically need you to use a pointer to anything; it takes a value and gives you a copy of the bytes but as a different type.

plain goblet
#

I didn't know you could do that, I'm mainly working through what the overview stated and I didn't see anything like that, unless I missed it. I ended up using that method to transfer the information to a struct, which is where it's supposed to be, and it worked as you stated. Interesting, thank you for the thorough explanation!

plucky willow
#

Surely you can do this a union? An array of 4 bytes and an int32 that share the same address?