2

I am running the following code on an Desktop x64 Intel architecture (gcc compiler, linux) and on an RaspberryPi Arm (gcc cross compiler).

quint32 id;

id=((quint32)ref[1]);
id|=((quint32)ref[2])<<8;
id|=((quint32)ref[3])<<16;
id|=((quint32)ref[4])<<24;

where ref is a QByteArray.

I noticed, that despite of casting quint32 (which is unsigned int) my Pc do the sign extension which causes error, when the given byte is a negative number. My code runs fine on Arm. Why does this happens? I thought casting should prevent this. Doesn't it?

   id|=((quint32)ref[4])<<24;

disassembly:

    mov    -0x160(%rbp),%rax
    mov    $0x4,%esi
    mov    %rax,%rdi
    callq  0x425af0 <QByteArray::operator[](int)>
    mov    %rax,%rcx
    mov    %edx,%eax
    mov    %rcx,-0x170(%rbp)
    mov    %eax,-0x168(%rbp)
    mov    -0x170(%rbp),%rax
    mov    %rax,-0x40(%rbp)
    mov    -0x168(%rbp),%rax
    mov    %rax,-0x38(%rbp)
    lea    -0x40(%rbp),%rax
    mov    %rax,%rdi
    callq  0x425aa0 <QByteRef::operator char() const>

    movsbl %al,%eax                                     #sign extension.

    shl    $0x18,%eax
    or     %eax,-0x148(%rbp)

I have also noticed, that compiler uses QByteRef return value instead of char. But it should not cause any error i guess.

from QByteArray help page :

QByteRef    operator[](int i)
char    operator[](int i) const
QByteRef    operator[](uint i)
char    operator[](uint i) const

Thanks in advance

Dati
  • 89
  • 1
  • 6
  • Seems to me you listed the one line that *can't* cause a problem since all sign bits would be shifted off the top. Otherwise, I can see that there might be a difference between platforms depending on whether the underlying `char` definition is signed or unsigned. – Hot Licks Mar 23 '14 at 00:31
  • 1
    Why not use QDataStream and read an uint32 from QByteArray that way? – paulm Mar 23 '14 at 00:31
  • Indeed the fourth bit cannot cause any error, i've just copied the wrong assembly example. I think, that char signess shouldn't bother me, because casting uint before shifting forces not to use sign extension. Am I wrong? Of course i can use id|=(((quint32)ref[2]) & 0xff)<<8; which solves my problem. – Dati Mar 23 '14 at 08:48
  • What Alan Stokes said. – Hot Licks Mar 23 '14 at 21:48

1 Answers1

2

When converting from a signed char to unsigned int (or other larger unsigned type) the language specifies sign extension happens first. To avoid that, cast the char to unsigned char as your first step. You shouldn't need any other cast - the increase in size should happen automatically.

Alan Stokes
  • 18,815
  • 3
  • 45
  • 64