There's also a fair amount of code whih relies on -1 ==
(int)0xFFFFFFFF.

Or is there any truly portable and efficient way to convert a sequence
of bytes (in big-endian order) to a signed integer?

Of course there is.  Assuming no padding bits:


int conv(unsigned char *c)
{
        unsigned int i, u, hibit;

        hibit = ~0U;
        hibit ^= (hibit >> 1);

        u = 0;
        for (i = 0; i < sizeof u; i++)
                u = (u << 8) + c[i];

        if ((u & hibit) == 0U)
                return u;

        u -= hibit;

        if ((unsigned int)-1 == (hibit | 1U))
                return -(int)u;

        return (int)u - (int)(~hibit) - ((unsigned int)-1 & 1U);
}


which generates


_conv:
        li r2,4
        li r0,0
        mtctr r2
L11:
        lbz r2,0(r3)
        slwi r0,r0,8
        addi r3,r3,1
        add r0,r0,r2
        bdnz L11
        mr r3,r0
        blr


with GCC 3.3 on Darwin, and


.conv:
        li 9,4
        li 0,0
        li 11,0
        mtctr 9
        .p2align 4,,15
.L2:
        lbzx 9,3,11
        slwi 0,0,8
        nop
        nop
        addi 11,11,1
        add 0,0,9
        nop
        nop
        rldicl 0,0,0,32
        nop
        nop
        nop
        nop
        bdnz .L2
        extsw 3,0
        nop
        nop
        nop
        nop
        blr


with a GCC-4.1.0 snapshot on powerpc64-unknown-linux-gnu (lots of
inefficiencies here, but nothing to do with the conversion itself).

Sorry, I couldn't test it on a ones' complement or sign-magnitude
machine -- just trust me it works (or embarrass me in public, if
a bug sneaked in while converting this to C) ;-)


Segher

Reply via email to