in reply to Re: pack and unpack with 8 bit integers
in thread pack and unpack with 8 bit integers

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!

Replies are listed 'Best First'.
Re^3: pack and unpack with 8 bit integers
by Anonymous Monk on Sep 22, 2014 at 14:48 UTC
    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!

        Thanks for the further information, I look forward to seeing your code.

        Unsigned integers of almost any size aren't a problem. You can mask a value before handing it off to pack, e.g. pack("C", 5 & 0b111) will get you the value 5 represented as the lowest 3 bits of the returned byte (the masking is not even necessary if you know your input is in the proper range). The inverse would be to unpack and then mask the value.

        It gets a little more complicated if you want signed integers, as you have to perform Sign extension as previously mentioned.

        In general, it is important to remember to check the range of the value you want to store, so that there are no unexpected overflows!

        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.

        When in doubt, test, test, test! Your two conversion functions to and from 3-bit numbers only require 8 test cases each (plus maybe a few to check for invalid values), that's no problem to write up, and you'll have immediate certainty that your conversion functions work. Even if it sometimes gets a little annoying to write lots of test cases, they are your safety net. And with some practice it gets easier and easier to properly modularize your code so that it's more easily tested.