3

I'm trying to convert some C++ Code that is written for MSVC so it can run on GCC or Clang.

The offending keyword is

UNALIGNED

pData is LPCBYTE

An example of the code is:

 INT8 some8Value =  *(UNALIGNED INT8 *)&(pData[offset]);

INT64 some64Value = *(UNALIGNED INT64 *)&(pData[offset]);

I think I understand what logically this code wants to do, it wants to read in the 1 byte from the pointer pointing to pData + offset.

The second one is saying read 8 bytes from the pData + offset pointer.

The confusing part is why is the first one UNALIGNED. I thought reading 1 byte is always aligned.

Or am I misreading the code somehow?

Is the cross platform way of doing this the following:

INT8 part1 = pData[offset];
INT8 part2 = pData[offset + 1];
...

And then combine the 8 parts (for example) in the INT64 case?

halivingston
  • 3,727
  • 4
  • 29
  • 42
  • Are you saying read 8 individual octets (assuming `pData` is `INT8*`), and then assemble them into an INT64 with appropriate bit-manip? If so, yes that can work if done properly, and is portable, though I would use `UINT8`. The only thing you need to take care on is shifting into the sign bit. It can be tricky to do right. How many places is this done, anyway ? – WhozCraig Mar 24 '16 at 07:50
  • @WhozCraig pData is LPCBYTE. In the second part I'm trying to suggest how I would write code that could construct this 8-byte integer. I'm looking for help here, how would I do it, if my way is incorrect? – halivingston Mar 24 '16 at 07:50
  • I concur with Frankie's answer, btw, assuming you have no intention of putting this on hardware that will puke on misaligned data. Intel can be pretty damn forgiving about that. Big Blue is *not*. Nor is Sparc, for that matter. – WhozCraig Mar 24 '16 at 07:54
  • I'll add that I do want it to run on ARM (Win10). I'm sure this is a common things people do but my google fu is letting me down on how to convert htis to portable code. – halivingston Mar 24 '16 at 08:12
  • 1
    FYI, the code makes nonportable assumptions about the bytewise representation of integers, so there's little chance to make it work. If your target architecture is little-endian, and I believe all MS Windows variants are, you could simply use `memcpy()`, which makes no assumptions about source or target alignments. – Ulrich Eckhardt Mar 24 '16 at 11:45

2 Answers2

2

This is a macro that equates to __unaligned when compiling for Itanium processors, and to nothing for all other CPU's. From MSDN (@ https://msdn.microsoft.com/en-us/library/ms177389.aspx):

When you declare a pointer with the __unaligned modifier, the compiler assumes that the pointer addresses data that is not aligned. Consequently, for an application that targets an Itanium Processor Family (IPF) computer, the compiler generates code that reads the unaligned data one byte at a time.

In your case simply equates it to nothing in a header:

#define UNALIGNED

Or, if you like, remove it from each place in the code.

EDIT: On ARM processors specifically can be used the qualifier __packed to specify for unaligned data, that existo for GCC as __attribute__ ((__packed__)), but doesn't exist for MSVC. For the latter the only choice is #pragma pack(1) which effect however should be limited to structures.
More info on SO answer Visual C++ equivalent of GCC's __attribute__ ((__packed__)).

Community
  • 1
  • 1
Frankie_C
  • 4,764
  • 1
  • 13
  • 30
  • I'm actually asking because this code will run on Windows 10 on ARM, and in addition to that Linux ARM where unaligned accesses may fail ... Apparently some Linux distros don't transparently do things for unaligned access. So if you could answer how to convert the code to read in any circumstance ... that would be awesome – halivingston Mar 24 '16 at 08:09
  • The modifier is specific to Itanium processors family. For all other processors ASAIK there is no need to qualify the access instructions. On an ARM processor the declaration of access to `INT8` shoulld suffice to generate instructions for byte aligned data. – Frankie_C Mar 24 '16 at 10:35
1

In GCC you can use aligned(1) attribute:

typedef int64_t __attribute__(( aligned(1) )) UNALIGNED_INT64;

UNALIGNED_INT64 unalignedPtr = pData + offset;
INT64 some64Value = *unalignedPtr;

from the GCC documentation:

When used on a struct, or struct member, the aligned attribute can only increase the alignment; in order to decrease it, the packed attribute must be specified as well. When used as part of a typedef, the aligned attribute can both increase and decrease alignment, and specifying the packed attribute generates a warning.

Read more here: Why does this alignment attribute have to be specified in a typedef?

gabonator
  • 391
  • 1
  • 9