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