2010-01-23 4 views
3

Чтобы использовать OSAtomicDecrement (специфическая для атома атомная операция), мне нужно предоставить 4-байтовый выровненный SInt32.Как обеспечить соответствие элемента 4 байта?

Работает ли этот вид кулинарной работы? Есть ли другой способ справиться с проблемами выравнивания?

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

    SInt32 *member_; 

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

ответ

5

Если вы находитесь на Mac, это означает GCC. GCC может автоматически выровнять переменные для вас:

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

Обратите внимание, что это не переносимо для компиляторов, так как это спецификация GCC.

+2

В чем преимущество этого решения, поскольку оно менее портативное (и дополнительное 4 байта используемого пространства нормально)? – gaspard

+0

Я действительно не хочу добавлять другой '#ifdef __gcc__' ... – gaspard

+0

-1: это гарантирует выравнивание хранилища для указателя. Да, так как это выровненное хранилище_ также будет выровнено, но это будет косвенным и запутанным. Если вы хотите порекомендовать задание выравнивания, просто выровняйте переменную (удалите структуру и просто создайте элемент '__attribute __ ((__ aligned (4))) SInt32 a_;' –

0

Я ничего не знаю о программировании Mac, а на мини-ЭВМ, которые я использовал для работы, указатели всегда были выровнены по 4 байта (слово) границ. IIRC, структуры тоже. Всегда была выделенная память.

4

Я бы предположил, что любой SInt32 уже выровнен, даже на Mac.

Для уточнения:

struct Foo { 
    SInt32 member; 
}; 

член всегда выровнены должным образом, если вы не упаковать структуру и поставить элемент после полукокса.

+0

Это будет случай PowerPC, но НЕ на x86. КПП - большой конец - слова должны быть выровнены, но на маленькой конечной цели нет никакой гарантии. – LiraNuna

+2

Никакой компилятор не сгенерировал бы код с целью использования неверных доступов на x86. Это может привести к серьезному поражению. –

+0

@ LiraNuna это неправда. Microsoft Visual C++ и GCC гарантируют выравнивание int до 4-байтовой границы на x86. Он документирован на MSDN, в случае Visual C++. – mloskot

-1

Если вы хотите принудительно настроить выравнивание в структуре, вы можете использовать битовые поля.

struct 
{ 
    Foo _hisFoo; 
    unsigned int dummyAlignment : 0; 
    Foo _myFoo; 
} 
+0

Поля бит-поля нулевой длины на следующую границу выравнивания базового объявленного типа. Это заставляет следующий член начинаться на границе байта (для битовых полей символов), 2-байтная граница (для краткости), 4-байтная граница (для int или long) или 8-байтная граница (для длинных длин). Заполнение не происходит, если макет памяти предыдущего члена заканчивается на соответствующей границе. – EvilTeach

1

int s являются 4 байта выровнены по умолчанию с любым из составителей OS X. Все, что вам нужно сделать, - это не умышленное нарушение этого выравнивания (например, выполнение неправильных следов указателей, маркировка вашей структуры как packed и т. Д.).

0

Если ваш компилятор поддерживает TR1 (или C++ 0x), вы можете использовать шаблон std::aligned_storage.

Чтобы выделить место для объекта с размером S и выравниванием A, вы можете выделить объект типа std::aligned_storage<S, A>::storage.

(Пространство имен может изменяться между составителями. Я думаю, ТР1 не определяет, какое пространство имен расширений должны быть помещены в. На MSVC, пространство имен std::tr1 используется)

Помимо этого, 32-битные целые числа уже 4-байтовый, выровненный компилятором (по крайней мере, на платформах, где естественное выравнивание 32-битных ints равно 4 байтам)