编译器常量指示内存对齐要求

时间:2015-02-11 16:55:21

标签: c portability platform memory-alignment

某些CPU架构(x86除外)不喜欢在未对齐的地址读取和写入多字节数字,以至于在检测到这种情况时会引发SIGBUS异常,并迫使程序员按字节顺序手动完成所有操作。虽然对于需要这个的平台可能无法做任何事情,但检查对齐并在允许未对齐访问的平台(例如x86)上执行逐字节操作将是愚蠢的。问题是: C / C ++编译器是否定义了表示对齐要求的常量

目前,我正在使用它:

#if defined(_M_IX86) | defined(__i386) | defined(__i386__) | defined(i386) | defined(_X86_)
    // Unaligned access is allowed.
#elif defined(_M_X64) | defined(__x86_64__) | defined(__x86_64) | defined(__amd64) | defined(__amd64__) | defined(_M_AMD64)
    // Unaligned access is allowed.
#else
    #define ALIGNED_ACCESS_ONLY
#endif

但它看起来太“家酿”:它不是指示当前硬件平台的实际属性,而是描述了我自己对x86-32和x86-64的考虑以及这些平台最常用的常量名称。

3 个答案:

答案 0 :(得分:1)

我在技术上并没有回答你提出的问题,但我提出了一个解决方法,以防你的问题的答案是否定的。

如果您的代码是在configure脚本的帮助下编译的,则可以测试是否需要对齐访问。 GNU autoconf具有执行此操作的功能:

http://www.gnu.org/software/autoconf-archive/ax_check_aligned_access_required.html

基本上它编译下面的小程序,运行它,并查看结果:

#include <stdio.h>
#include <stdlib.h>

int main()
{
  char* string = malloc(40);
  int i;
  for (i=0; i < 40; i++)
  {
    string[[i]] = i;
  }

  {
     void* s = string;
     int* p = s+1;
     int* q = s+2;

     if (*p == *q) { return 1; }
  }
  return 0;
}

答案 1 :(得分:0)

我在memcpy的实现中看到的解决方案不需要任何检查。基本上,您开始每个字节复制数据字节,直到达到所需对齐的地址倍数 之后,您可以开始复制字大小的数据块,并使用对齐的地址(循环展开,矢量化,...)带来的所有好处。

尽管如此,你可以利用大块数据充分利用它。

显然,clanggcc都没有定义任何宏来通知未对齐的访问。 (gcc/clang -E -dM - < /dev/null -march=native)。
您可能需要考虑的一些想法:

  • 首先减少需求:使用指针时出现问题。尽量避免这种情况,重构你处理数据的方式。
  • asm:编写与平台相关的asm来加载/存储与未对齐访问的对象,尽管它在很大程度上取决于您正在使用的平台。
  • SSE允许不对齐访问。

答案 2 :(得分:-3)

OP:C / C ++编译器是否定义了一个表示对齐要求的常量? 是。 max_align_t是最大对齐要求的类型。

如果sizeof(max_align_t) > 1,则需要进行一些对齐。

在C11之前,请参阅Compiler constant indicating memory alignment requirement