views:

406

answers:

6

In order to use OSAtomicDecrement (mac-specific atomic operation), I need to provide a 4-byte aligned SInt32.

Does this kind of cooking work ? Is there another way to deal with alignment issues ?

struct SomeClass {
  SomeClass() {
    member_  = &storage_ + ((4 - (&storage_ % 4)) % 4);
    *member_ = 0;
  }

  SInt32 *member_;

  struct {
    SInt32 a;
    SInt32 b;
  } storage_;
};
A: 

I know nothing about Mac programming but on minicomputers that I used to work on, pointers were always aligned on 4-byte (word) boundaries. IIRC, structs were too. Allocated memory always was.

Mick Sharpe
+4  A: 

If you're on a Mac, that means GCC. GCC can auto align variables for you:

  __attribute__((__aligned__(4))) int32_t member_;

Please note that this is not portable across compilers, as this is GCC specific.

LiraNuna
What is the benefit of this solution since it's less portable (and an extra 4 byte of space used is ok) ?
Gaspard Bucher
I don't really want to add another `#ifdef __gcc__`...
Gaspard Bucher
-1: this makes sure that the storage for the pointer is aligned. Yes, since it's aligned storage_ would also be aligned but that is indirect and confusing. If you want to recommend specifying alignment, just directly align the variable (drop the struct and just create a member `__attribute__((__aligned(4))) SInt32 a_;`
R Samuel Klatchko
You are aligning the pointer, but not initializing it.
Richard Pennington
There is NO "extra 4 bytes used", GCC simply relocates the class to fit your demands. There is also NO WAY of doing so reliably across compilers, MSVC has such an option (__declspec align?). You have special needs that only the linker can accommodate and you think you can get away without compiler-specific options? The pointer was a left-over from the pasted code, it should not be there (edited out).
LiraNuna
@LiraNuna the 4 extra bytes exist in my example, not in yours. Sorry for the confusion. You might be right, I might not be able to avoid compiler dependencies...
Gaspard Bucher
Mac doesn't necessarily mean GCC. One could use clang/llvm, ICC supports OS X, as do a few other compilers.
Stephen Canon
@Gaspard: You don't need any compiler dependant code. The members are already aligned.
Richard Pennington
@Richard: Nothing in the C++ specification says that the members are aligned. They are as such because of **compiler optimization** for faster memory access. This does not, in any way **guarantee** of that. Another architecture/compiler might find it better to optimize it otherwise.
LiraNuna
He's not talking about a standard. He's talking about a specific application and alignment on the mac. I happen to know how gcc and clang deal with alignment for the x86 under OSX, so I thought giving him the right answer was OK.
Richard Pennington
Removing my down vote as you fixed the pointer issue. That said, why does your example still include the storage_ member?
R Samuel Klatchko
@LiraNuna: You're correct that it's not guaranteed by the C++ spec, but the C++ spec is not the only relevant document. The OS X abi rules are quite clear that `int`s are 4 byte aligned by default.
Stephen Canon
@LiraNuna Can you remove the storage thing and use "int32_t" instead (that's the type used in OSAtomic.h).
Gaspard Bucher
@Richard I need to be absolutely sure that my code does not produce hazardous results now or in the future and explicitly requiring alignment seems like a good idea.
Gaspard Bucher
@Gaspard: That's OK. I've already used up all of my 200 points today, it seems. ;-)
Richard Pennington
+4  A: 

I would guess that any SInt32 is already aligned, even on a mac.

To clarify:

struct Foo {
    SInt32 member;
};

member is always aligned properly, unless you pack the structure and put member after a char.

Richard Pennington
This will be the case on PowerPC, but NOT on x86. PPC is big endian - words must be aligned, but on little endian, there is no guarantee of that.
LiraNuna
No compiler would generate code on purpose that used misaligned accesses on an x86. It would cause a severe performance hit.
Richard Pennington
@LiraNuna it is not true. Microsoft Visual C++ and GCC guarantee alignment of int to 4-byte boundary on x86. It is documented on MSDN, in case of Visual C++.
mloskot
Absolutely correct. All of the 4-byte basic types are 4-byte aligned by default on OS X.
Stephen Canon
A: 

If you want to force a nice alignment in a structure, you can use bit fields.

struct 
{
   Foo _hisFoo;
   unsigned int dummyAlignment : 0;
   Foo _myFoo;
}
EvilTeach
A zero-length bit field pads to the next alignment boundary of its base declared type. This causes the next member to begin on a byte boundary (for char bit fields), 2-byte boundary (for short), 4-byte boundary (for int or long), or 8-byte boundary (for long long). Padding does not occur if the previous member's memory layout ended on the appropriate boundary.
EvilTeach
+1  A: 

ints are 4 byte aligned by default with any of the OS X compilers. All you need to do is not intentionally break that alignment (e.g. by doing improper pointer casts, marking your structure as packed, etc).

Stephen Canon
A: 

If your compiler supports TR1 (or C++0x), you can use the std::aligned_storage template.

To allocate space for an object with size S and alignment A, you can allocate an object of type std::aligned_storage<S, A>::storage.

(The namespace may vary between compilers. I think TR1 doesn't specify which namespace the extensions must be placed in. On MSVC, the namespace std::tr1 is used)

Apart from this, 32-bit integers are already 4-byte aligned by the compiler (at least on the platforms where the natural alignment of 32-bit ints is 4 bytes)

jalf