John M. Dlugosz has asked for the wisdom of the Perl Monks concerning the following question:

I see a warning in a utility I've never seen before: Character in "c" format wrapped at whatever.perl line 109. The line in question is:
my $last_byte = pack('c', hex 'DC'); # line 109
Naturally, I did not write this.

What is the warning complaining about? I'm supposing it warns in Perl 5.8, and didn't in older versions.

—John

Replies are listed 'Best First'.
Re: What is this warning? 'Character in ''c'' format wrapped at ...'
by bart (Canon) on May 15, 2003 at 20:23 UTC
    'c' as a pack template is related to signed characters, range -128 to 127. 'C' is the same for unsigned characters, range 0 to 255. Your hex number is 220, which is not in range for the signed numbers...

    So your unsigned number is wrapped so it fits into a signed bytes, completely in agreement with the rules of 2's complement. The lower 8 bits are the same, but the additional higher bits are thusly chosen so the resulting number is in range: that number is -36.

    print unpack 'c', pack 'C', 220;

    Don't use the 'c' template if you don't plan on using signed numbers. Use 'C'.

Re: What is this warning? 'Character in ''c'' format wrapped at ...'
by Ovid (Cardinal) on May 15, 2003 at 19:56 UTC

    I've not seen it before, but it appears to be related to how ASCII characters are handled with pack. From this bug report, it mentions that error occurs when dealing with non-ASCII characters. The fix was to change from pack "c"... to pack "C".... The pack documentation also hints at this.

    The source code that generates this tends to suggest that you may just need to switch your template (of course, that really depends upon what you're trying to do with pack):

    case 'C': case 'c': while (len-- > 0) { fromstr = NEXTFROM; switch (datumtype) { case 'C': aint = SvIV(fromstr); if ((aint < 0 || aint > 255) && ckWARN(WARN_PACK)) Perl_warner(aTHX_ WARN_PACK, "Character in \"C\" format wrapped"); achar = aint & 255; sv_catpvn(cat, &achar, sizeof(char)); break; case 'c': aint = SvIV(fromstr); if ((aint < -128 || aint > 127) && ckWARN(WARN_PACK)) Perl_warner(aTHX_ WARN_PACK, "Character in \"c\" format wrapped"); achar = aint & 255; sv_catpvn(cat, &achar, sizeof(char)); break; } } break;

    Cheers,
    Ovid

    New address of my CGI Course.
    Silence is Evil (feel free to copy and distribute widely - note copyright text)

      Looks like you want 'C' for bytes, and 'c' for (single-byte/ASCII) characters. The output of 'c' is signed while the output of 'C' is unsigned.

      --
      [ e d @ h a l l e y . c c ]

      Thanks. So it means that 0xDC is not in the range of a signed byte, but it gives the same 8-bit result anyway.
      perl -e "print (pack('c',0xDC) eq pack('C',0xDC))"
      prints 1.

      I think it's simpler just to say "\xDC", though the pack may be clearer in context, among a list of things of various lengths.

      —John