Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I get a warning for an unaligned pointer but not a reference

I have project I'm porting from from 32 bit Windows to 64 bit, which includes code that can be simplified as follows:

void FuncA(double &x)
{
    x = 0;
}

void FuncB(double *x)
{
   *x = 0;
}

#pack(1)

struct 
{
   char c;
   double x;
} MyStruct;

#pack();

void MyFunc()
{
   MyStruct M;
   FuncA(M.x);  // This is OK
   FuncB(&M.x); // This generates a warning C4366
}

When compiling under VS2010 SP1 targeting 64 bit, calling FuncB with a member of a packed struct generates the following warning:

warning C4366: The result of the unary '&' operator may be unaligned

Whereas calling FuncA does not. I would have thought that both cases would have compiled down to pretty much the same code. Are references somehow safer from alignment problems than the equivalent pointer? Or is it that MSVC is simply not issuing a warning where it should? The project requires the struct packing is maintained, so my choices are to either change FuncB to

void FuncB(__unaligned double *x)
{
   *x = 0;
}

or to simply use FuncA in all such cases. The latter would be preferable as it is more portable, but I'm wondering is it going to work or is the lack of a warning in the reference case simply a shortcoming in the compiler?

Edit: The Microsoft help entry for this error is here. The __unaligned help suggests that failing to heed this warning will cause exceptions to be thrown on Itanium processors. Further trawling around MSDN suggests there may be issues surrounding unaligned references. While this may not cause problems for my current users, if the Itanium architecture becomes more widely used in future, I could be setting up a support nightmare. Plan is now to add specific wrappers for all the functions that use the packed structures, to avoid the pointers and the __unaligned keyword.

like image 715
SmacL Avatar asked Jun 17 '13 11:06

SmacL


Video Answer


1 Answers

A reference and a pointer is pretty much the same thing (under the hood, so to speak), so from a safety perspective, it's no different. It's probably more of an oversight and/or that the compiler is less concerned by references, as they can't be passed outside of a C++ environment (although I'm inclined to think that it's simply an oversight).

It may also be that the compiler is more concerned by pointers because it is more likely that pointers are used for performance, where you want to iterate over a range of double values (e.g. by allocating more space than the struct itself uses, and storing further double values after it) - you can't do that with a reference. Since unaligned access is at least slower than an aligned access, this can have consequences for performance, and in some systems, it will cause a OS trap, which will either "fix up" the unaligned access (at a pace of a couple of orders of magnitued slower than an ordinary aligned access), or the OS simply says "Your program caused an unaligned access, I'm killing it".

There are also issues with multithreading, as unaligned access may not be atomically updating the data. Of course, you should use std::atomic or similar for data shared between threads.

The x86 is perfectly able to read a double from an unaligned address. I think Itanium isn't but I'm suspecting you don't use that processor anyway, statistically speaking. Other, older architectures, such as Alpha may have problems reading unaligned memory.

like image 83
Mats Petersson Avatar answered Oct 25 '22 22:10

Mats Petersson