http://www.perlmonks.org?node_id=672660

blahblahblah has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to port a bit of old C code to perl. I generated a ton of test cases from the C program output, wrote my Perl code, and then compared the results for the same inputs. Some cases are successful; others are not. I put in a bunch of debugging and fixed some simple things -- incorrect array indexes; for loops translated wrong; etc. -- but I'm hung up on something I can't figure out. Here is the C code:
return (func(token4) & 95) | (func(token5) & 32 | func(token5) & 128); /* "func" is defined as: */ unsigned long func (c) unsigned char *c;
In my failing case, the values of token4 & token5 are 0 and 32, resulting in:
(0 & 95) | (32 & 32) | (32 & 128)
The C code evaluates this to a result of zero. I tried porting the same to perl, and for some of my test cases it matches the C result, but for this particular case the following perl code prints 32:
perl -e 'print ((0 & 95) | (32 & 32) | (32 & 128))'
I read perlop but didn't find anything meaningful to me. It seems from Will/Can Perl 6 clean up the bit-wise operator precedence mess? that Perl tries to have the same operator precedence as C. Do I need to pack my data into something other than a plain old scalar? I'm not well versed in C or in this sort of bitwise manipulation in Perl. Can anyone spot an obvious problem or offer some pointers?

Thanks,
Joe

Replies are listed 'Best First'.
Re: help porting a line of bitwise C code to perl
by dsheroh (Monsignor) on Mar 07, 2008 at 05:03 UTC
    func(token5) is not returning 32. (32 & 32) is non-zero (32, to be exact) and a bitwise-or between a non-zero integer and any other integer can never be zero, regardless of the language you're using.

    Either that, or C is processing the bitwise operators in a different order than you think it is, resulting in your parentheses being misplaced, although I can't readily think of any order in which (func(token5) & 32 | func(token5) & 128) could be handled that would produce zero when func(token5) returns 32.

Re: help porting a line of bitwise C code to perl
by BrowserUk (Patriarch) on Mar 07, 2008 at 05:32 UTC

    Not enough information.

    Are the values token4 =  0 & token5 = 32 the values passed into func(), or the values returned by func()?

    Because if those are the values coming out of func(), your C program is broken:

    1. 0 & 95 = 0. (0 & anything == 0)
    2. 32 & 32 = 32. (X & X) always == X
    3. 32 & 128 = 0.
    4. 0 | 32 | 0 = 32.

    But if the values you've given are the values going into func(), then as you've only supplied a declaration (was that form ever legal C?), we cannot tell what might come out for those inputs.

    Further more, the only way I can interpret that declaration of func(), is that it is expecting a pointer to an unsigned char as its input. And the likelyhood of 0 and 32 being valid pointers is minimal.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      was that form ever legal C?

      Yeah, it was (for certain values of 'legal'). That form of function prototype is known as 'K&R style'... There are - in the broadest possible terms - two versions of C. The first is usually called 'K&R C', from the initials of the authors of the canonical textbook (The C Programming Language). The second is called 'ANSI C' or 'ISO C', from the initials of the American and international standards bodies who, well, standardized the language.

      Anyway, when ANSI standardized the C language it got a major overhaul, which included a new form of function declaration. The old form will still compile on lots of compilers, but the new form (usually called 'ANSI style') is much better.


      email: perl -e 'print reverse map { chr( ord($_)-1 ) } split //, "\x0bufo/hojsfufqAofc";'
        from the initials of the authors of the canonical textbook (The C Programming Language).

        Yes. My copy sits on the shelf above my computer. It has a loose front cover, is a faded yellow color, has the ISBN number 9-130110163-3 and dates from 1978.

        And on page 218/section 18.4 External definitions it give the following set of possibilities:

        program: external-definition external-definition program external definition: function-definition data-definition function-definition: type-specifier(opt) function-declarator function-body function-declarator declarator ( parameter-list(opt) ) parameter-list: identfier identifier , parameter-list function-body: type-decl-list function-statement function-statement: { declaration-list(opt) statement-list }

        I don't think you you'll find a much earlier revision than my copy, indeed I can't find any sign that it is a revised edition at all, but I can't see any interpretation of the above, that means that:

        unsigned long func (c) unsigned char *c;

        was ever a legal function declaration.

        There are certainly no examples in the book that look like that, though there are precious few examples of function declaration. I've been doing C a long time and I've always declared function parameters inside the parens. I well remember the old DECUS compiler used to permit some extraordinary code, which why it was so favoured by the Obfuscated-C entrants, but I still do not recall seeing people use the above declaration form.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: help porting a line of bitwise C code to perl
by Anonymous Monk on Mar 07, 2008 at 04:42 UTC
    I put that into my c++ compiler, and it prints 32, same as my perl.
Re: help porting a line of bitwise C code to perl
by blahblahblah (Priest) on Mar 07, 2008 at 05:19 UTC
    Thank you esper and anonymonk. It turns out my test cases were wrong. (I had hand-edited the test data at one point to work on a few failing cases, and I didn't undo my changes properly.) I went back to my original case file and now every one of my tests passes.