in reply to pack and unpack with 8 bit integers

The problem is that the i template needs at least 32 bits, but you're only giving it 8. The $size argument to bin2dec should be 32, but even then your function won't always work depending on the endianness of your system!

$ perl -wMstrict -le 'print unpack("B*",pack("i",3))' 00000011000000000000000000000000 $ perl -wMstrict -le 'print unpack("i",pack("B*", "00000011000000000000000000000000"))' 3 $ perl -wMstrict -le 'print unpack("i",pack("B*", "00000000000000000000000000000011"))' 50331648 $ perl -wMstrict -le 'print unpack("i",pack("B*","00000011")).""' Use of uninitialized value in concatenation (.) or string at -e line 1 +. $ perl -wMstrict -le 'print unpack("c",pack("B*","00000011"))' 3

(Note the use of "B*" instead of "B$size".) Some more general observations:

The i template is system-dependent. Unless the binary data itself is system-dependent, such as from C structs, I'd only use the system-independent formats, in this case for example the cCnNvV formats since those have a fixed size and endianness.

You say want to use i, but then only want handle 8 bits, that does not go together - why not use c to begin with? Also, you're not checking that your values will actually fit in 8 bits!

Lastly, I suspect you've got an XY Problem and you might want to explain to us what you're trying to accomplish overall. Don't worry about asking too many questions, but I would suggest you play around with pack and unpack a bit more, like I did above!

Replies are listed 'Best First'.
Re^2: pack and unpack with 8 bit integers
by thanos1983 (Parson) on Sep 22, 2014 at 13:46 UTC

    Hello Anonymous Monk,

    I was afraid that the int size of "i" would be 32 bits, because I have been playing around and I could get the correct output with 32

    perl -wMstrict -le 'print unpack("i",pack("B32","00000011"))' 3

    I was hopping since I get no error when I am using pack I would not have any problems when I will use unpack.

    perl -wMstrict -le 'print unpack("B8",pack("i",3))' 00000011

    I noticed the: (Note the use of "B*" instead of "B$size".)

    Ok then let me describe from the beginning what I am trying to achieve.

    I want to convert decimal numbers on three-bit integer (signed and unsigned). So far I have managed to achieve it with the following piece of code:

    #!/usr/bin/perl use strict; use warnings; sub dec2bin { my $bits = shift; my $size = shift; my $template = shift; return unpack("B$size", pack($template, $bits)); } sub bin2dec { my $bits = shift; my $size = shift; my $template = shift; return unpack($template, pack("B$size",substr("0" x $size . $bits +, -$size))); } my $int2bin = dec2bin( 3 , 8 , "c" ); print "Int2bin: ".$int2bin."\n"; my $binary2int = bin2dec( $int2bin , 8 , "c" ); print "Decimal from binary: ".$binary2int."\n";

    My hesitation and the reason that I created the question was that I read on pack i A signed integer value. , I A unsigned integer value. (This 'integer' is _at_least_ 32 bits wide. Its exact size depends on what a local C compiler calls 'int'.) , c A signed char (8-bit) value. and finally C An unsigned char (octet) value.. This is the reason that I was trying to find a solution by using "i" and "I".

    At this point I do not know if I should use "c" or "C" as an alternative to int and unsigned int for my task.

    Thank you for your time and effort, reading and replying to my question.

    Seeking for Perl wisdom...on the process of learning...not there...yet!
      I want to convert decimal numbers on three-bit integer (signed and unsigned).

      Ok, but why? That's what is meant by an XY Problem - are you doing this for example because you're communicating with some other software that requires data in this format (if so, what is that format? perhaps show some sample data?), just for practice / fun, etc.? It can help to know what the broader picture is. In this case the main reason being that Perl's pack and unpack are not always the right tool for the job (also there are some pack templates that I'd stay away from as they can get too complex). So far, I've only found them useful for decoding C structs, handling binary data in network protocols, or for debugging.

      Anyway, to get to your questions:

      ... This is the reason that I was trying to find a solution by using "i" and "I".

      I find the best way to think about pack templates is C data types. Think of i as int, and that'll make it clear that i is (unfortunately) not "as many bits as I want".

      At this point I do not know if I should use "c" or "C" as an alternative to int and unsigned int for my task.

      As said before, unless you know that you want the system-dependent formats, stick with the system-independent formats cCnNvV, perhaps with the ! modifier to make them signed, or sl with one of the <> modifiers to force endianness. Then pick according to required size, signedness, and endianness.

      I want to convert decimal numbers on three-bit integer (signed and unsigned).

      A three-bit signed integer? I don't think Perl has built-in support for that, so you'll probably need to build your own Sign extension, as some quick searching has not (yet) shown me any CPAN modules. If you want to do it on binary values, see perlop for the bitwise ops, also maybe vec; or you could do it on the string representation (which will probably be a little slower). Or, with just 8 possible values, a look-up table may be the easiest way!

        Hello Anonymous Monk,

        First of all I want to say a big thank you for the analytic answer to my question.

        You helped me to understand a lot, not only about the binary process on Perl but also how my future questions should be written so people can follow easier and sujest possible alternative solutions.

        Well I am working on Simple Network Time Protocol (SNTP). I have created a simple version UDP SNTP Client/Server RFC. Where I was introduced to the idea to submit my code to CPAN library.

        So I decided to add all the features and details that the RFC 2030 describes.

        I have created the improved version and it seems fine from my point of view. I will post it possibly today or tomorrow to ask for possible minor improvements from all the expert Monks here.

        So in order to make my script as generic as possible I wanted to follow the instructions "by letter". But to be 100% honest it would not make a difference if I have a 3 bit int "i" or 3 bit character "c". The representation is only an integer number 7. So I want to believe that it will not be a problem, with the 8 bit character that I am cutting to 3 bit. The program on both sides client and server can encode and decode the number. So I assume there is no problem about it.

        Since I am not really experienced with binaries I tried to do my best, and I hope that the scripts will have minimum possible bugs.

        So more or less I described my task that actually I am doing for fun while I am trying to improve my skills and keep my mind busy.

        Again thank you for your time and effort answering my question and providing such an analytic answer.

        Seeking for Perl wisdom...on the process of learning...not there...yet!