Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

reinterpret_cast<> and portabilty

I've read that reinterpret_cast<> can be dangerous if not used properly. So I believe that i was using it properly ;). I found it's good to use if I've templates classes and type conversion is required on that. But recently I've read that reinterpret_cast<> is non-portable too. I'm sad for this point. What's the reason? Take the following code,

void Disp(int* val)
{
    for (int i=0; i < SZ; ++i)
    {
        cout << *(val+i) << " ";
    }
    cout << endl;
}

int main()
{
    int arr[SZ];
    Disp(arr);

    unsigned char* ptr = reinterpret_cast<unsigned char*>(arr);
    for (unsigned char* i = ptr; i < (ptr + (SZ * sizeof(int))); i++)
    {
        *i = 0;
    }
    Disp(arr);
    return 0;
}

Now the outputs:

1174214872 32767 4196789 0 568392584 58 4196720 0 0 0 
0 0 0 0 0 0 0 0 0 0 

Machine type: Linux 2.6.32-358.11.1.el6.x86_64 #1 x86_64 x86_64 x86_64 GNU/Linux

975580 -16506540 -13369152 0 -4202936 67876 3 -4202836 4 -4202828 
0 0 0 0 0 0 0 0 0 0 

Machine type: SunOS DELPHI 5.10 Generic_142900-01 sun4u sparc SUNW,Netra-240

I've copied the outputs of the same program, both in Linux and Solaris. I'm new to portability issues. So can anyone please tell me, if I'm using something like this in my code, will that cause any portability issues? Even if not with this code, is there a chance for surprises (undefined behavior) when the code get complex (with dynamic allocation and all) and running for long hours. Thanks for the help.

like image 403
sarath Avatar asked May 01 '14 03:05

sarath


2 Answers

The portability issue with reinterpret_cast<> lies in the fact that different CPUs store numbers differently in memory. Some store them from the least significant byte up to the most significant one (little endian), others do it precisely the other way around (big endian). Some even use some weird byte order like 1 0 3 2, don't ask me why.

Anyway, the consequence of this is, that reinterpret_cast<> is portable as long as you do not rely on the byte order in any way.

Your example code does not rely on byte order, it treats all bytes the same (setting them to zero), so that code is portable. If you would use a reinterpret_cast<> to copy some data object on the same machine without interpreting the bytes, the code would also be portable (memcpy() does this).

What is not portable is stuff like taking a look at the first byte to determine the sign of a number (works only on big endian machines). If you try to transfer data from one machine to another by just sending the result of reinterpret_cast<char*>, you are also in trouble: the target machine may use a different byte order than the source machine, completely misinterpreting your data.

I would say that it is wrong to say that the reinterpret_cast<> is non-portable, it simply exposes a machine detail to the C++ code which is machine-specific. And any code that relies on that machine detail is non-portable.

like image 139
cmaster - reinstate monica Avatar answered Sep 18 '22 19:09

cmaster - reinstate monica


There are some problems with this code.

  • You're displaying the contents of an uninitialized array. There's really no point to it.
  • You're hard coding the size of your loop, assuming sizeof(int) == 4. If you are on a machine with a different size int, this will be non-portable.
  • If you were filling memory with any value other than zero, you'd need to worry about the endianness of the processor.

Edit: I see you've edited out the hard-coded magic constant 4 so point 2 no longer applies.

like image 31
Mark Ransom Avatar answered Sep 18 '22 19:09

Mark Ransom