Forum: Ruby unpack 4 bytes to a signed integer

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
52d83a4ca564de7e67f06855c85ff1d4?d=identicon&s=25 w wg (Guest)
on 2007-01-19 16:31
(Received via mailing list)
Hi
I' m using unpack to convert 4 bytes to local integer, but ruby just
supply the "N" modifer  which means unsigned long integer.

My questions is :
How to unpack 4 bytes to a signed integer ?

Thank you.
6b0967f63d03e99b6c07a3f5ed224c77?d=identicon&s=25 Erik Veenstra (Guest)
on 2007-01-19 16:31
(Received via mailing list)
s = 0xFF.chr * 4
i = s.unpack("L").shift

p i
p 2**32-1
47b1910084592eb77a032bc7d8d1a84e?d=identicon&s=25 Joel VanderWerf (Guest)
on 2007-01-19 16:31
(Received via mailing list)
w wg wrote:
> Hi
> I' m using unpack to convert 4 bytes to local integer, but ruby just
> supply the "N" modifer  which means unsigned long integer.
>
> My questions is :
> How to unpack 4 bytes to a signed integer ?

The best way I've found is to unpack with N (to get the swapping right)
and then do some arithmetic to interpret the unsigned value as signed:

x = -123
s = [x].pack("N")
   # Note that for _pack_ there is no need for a
   # special signed version of N

p s    # ==> "\377\377\377\205"

length = 32
mid = 2**(length-1)
max_unsigned = 2**length
to_signed = proc {|n| (n>=mid) ? n - max_unsigned : n}

p to_signed[s.unpack("N").first]  # ==> -123



This is all very hard for me to remember, so I've written a library to
do it, bit-struct (http://redshift.sourceforge.net/bit-struct). This
makes life easier:

require 'bit-struct'

class Packet < BitStruct
   signed    :x, 32
end

pkt = Packet.new
pkt.x = -123

p pkt.to_s  # ==> "\377\377\377\205"
p pkt.x     # ==> -123

# given string data from a network:
pkt2 = Packet.new("\377\377\377\205")
p pkt2.x     # ==> -123
52d83a4ca564de7e67f06855c85ff1d4?d=identicon&s=25 w wg (Guest)
on 2007-09-25 22:32
(Received via mailing list)
But the "i" and "I" modifer don't care bytes order.
I'm reading data from network using IO#sysread, I need receive integer
, not unsigned integer.

Thank you for your reply.

2007/1/15, Mike Stok <mike@stok.ca>:
6b0967f63d03e99b6c07a3f5ed224c77?d=identicon&s=25 Erik Veenstra (Guest)
on 2007-09-25 22:37
(Received via mailing list)
s = 0xFF.chr * 4
i = s.unpack("L").shift

p i
p 2**32-1
2ffac40f8a985a2b2749244b8a1c4161?d=identicon&s=25 Mike Stok (Guest)
on 2007-09-25 22:38
(Received via mailing list)
On 15-Jan-07, at 10:10 AM, w wg wrote:

> But the "i" and "I" modifer don't care bytes order.
> I'm reading data from network using IO#sysread, I need receive integer
> , not unsigned integer.
>
> Thank you for your reply.

OK then, what about "V"? "treat 4 characters as an unsigned long in
little-endian byte order"

The N uses network byte order "big-endian"

Mike


>> > My questions is :
>> --
>>
>
>
> --
> --
> WenGe Wang
>
>

--

Mike Stok <mike@stok.ca>
http://www.stok.ca/~mike/

The "`Stok' disclaimers" apply.
2ffac40f8a985a2b2749244b8a1c4161?d=identicon&s=25 Mike Stok (Guest)
on 2007-09-25 22:38
(Received via mailing list)
On 15-Jan-07, at 8:29 AM, w wg wrote:

> Hi
> I' m using unpack to convert 4 bytes to local integer, but ruby just
> supply the "N" modifer  which means unsigned long integer.
>
> My questions is :
> How to unpack 4 bytes to a signed integer ?


There are "i" and "I" for signed and unsigned integer respectively,
which deals in the local size of integer.

Hope this helps,

Mike

--

Mike Stok <mike@stok.ca>
http://www.stok.ca/~mike/

The "`Stok' disclaimers" apply.
52d83a4ca564de7e67f06855c85ff1d4?d=identicon&s=25 w wg (Guest)
on 2007-09-25 22:39
(Received via mailing list)
I tried your codes, it works exactly as what I expected. I havn't
tried your library, but I think it should get the correct result too.

Thank you.
This topic is locked and can not be replied to.