如何确保成员的对齐方式为4字节?

4
为了使用OSAtomicDecrement(mac特定的原子操作),我需要提供一个4字节对齐的SInt32。
这种烹饪方式可行吗?是否有其他处理对齐问题的方法?
struct SomeClass {
  SomeClass() {
    member_  = &storage_ + ((4 - (&storage_ % 4)) % 4);
    *member_ = 0;
  }

  SInt32 *member_;

  struct {
    SInt32 a;
    SInt32 b;
  } storage_;
};
6个回答

5

如果您正在使用Mac,那么意味着GCC。GCC可以自动为您对齐变量:

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

请注意,这不是跨编译器可移植的,因为这是GCC特有的。

2
这个解决方案的好处是什么,因为它不太可移植(使用额外的4字节空间可以接受)? - Anna B
1
没有“额外使用4个字节”,GCC只是重新定位类以适应您的需求。在编译器之间可靠地进行这样的操作也是不可能的,MSVC有这样一个选项(__declspec align?)。您有特殊需求,只有链接器可以满足,并且您认为可以不使用特定于编译器的选项吗?指针是从粘贴的代码中剩下的,它不应该存在(已编辑)。 - LiraNuna
@LiraNuna,这4个额外的字节存在于我的示例中,而不是你的示例中。对于造成的混淆我感到抱歉。也许你是对的,我可能无法避免编译器依赖... - Anna B
他不是在谈论标准,而是在谈论Mac上的特定应用和对齐方式。我碰巧知道gcc和clang在OSX下如何处理x86的对齐,所以我认为给他正确的答案是可以的。 - Richard Pennington
由于您已经解决了指针问题,我将取消我的反对票。话虽如此,为什么您的示例仍然包括storage_成员? - R Samuel Klatchko
显示剩余8条评论

4
我猜测任何SInt32都已经对齐,即使在Mac上也是如此。
澄清一下:
struct Foo {
    SInt32 member;
};

成员变量总是对齐正确的,除非您将结构体打包并在一个字符后面放置成员变量


这在PowerPC上是这样的,但在x86上不是。PPC是大端 - 单词必须对齐,但在小端上,不能保证这一点。 - LiraNuna
2
没有编译器会故意生成在x86上使用未对齐访问的代码。这将导致严重的性能损失。 - Richard Pennington
@LiraNuna 这不是真的。Microsoft Visual C++ 和 GCC 保证在 x86 上将 int 对齐到 4 字节边界。这在 MSDN 上有记录,对于 Visual C++ 来说。 - mloskot
完全正确。在OS X上,默认情况下,所有4字节基本类型都是4字节对齐的。 - Stephen Canon

1

int在任何OS X编译器中默认为4字节对齐。您所需要做的就是不要故意破坏这种对齐方式(例如通过不正确的指针转换、将结构标记为packed等)。


0

我对Mac编程一无所知,但在我曾经工作的小型计算机上,指针总是对齐在4字节(单词)边界上。如果我没记错的话,结构体也是如此。分配的内存总是这样。


0

如果您的编译器支持TR1(或C++0x),则可以使用std::aligned_storage模板。

为了为大小为S和对齐方式为A的对象分配空间,您可以分配一个类型为std::aligned_storage<S,A> :: storage的对象。

(命名空间可能因编译器而异。我认为TR1没有指定扩展必须放置在哪个命名空间中。在MSVC上,使用命名空间std::tr1

除此之外,32位整数已经由编译器进行4字节对齐(至少在32位int的自然对齐方式为4字节的平台上)


-1
如果您想在结构体中强制进行良好的对齐,可以使用位域。
struct 
{
   Foo _hisFoo;
   unsigned int dummyAlignment : 0;
   Foo _myFoo;
}

一个零长度的位域会填充到其基本声明类型的下一个对齐边界。这将导致下一个成员从字节边界(对于char位域)、2字节边界(对于short)、4字节边界(对于int或long)或8字节边界(对于long long)开始。如果前一个成员的内存布局已经在适当的边界上结束,则不会发生填充。 - EvilTeach

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接