便携式告诉编译器在没有压制警告的情况下对齐是否正常?

时间:2016-01-23 19:21:08

标签: c gcc casting clang compiler-warnings

我们运行的测试之一是使用-Wcast-align进行编译。当浮点数,双精度数和积分数之间出现错误的强制转换时,它尤其有用(它有时会导致 SIGBUS ,IIRC)。

我们的代码基本上执行以下操作。实际案例涉及的更多,但这是用法的本质:

typedef uint64_t word64;

static const size_t SIZE = ...;
word64 buffer[SIZE] = ...;

DoSomethingWithBuffer(const byte* buff, size_t size)
{
    word64* ptr = (word64*)buff;
    ...
}

缓冲区在8或16字节边界上对齐。我已经使用手动代码审查和运行时断言验证了对齐方式。

问题是GCC和Clang警告说数据是不对齐的。它已经发生了近2000次,所以我可能会失去真正的发现。例如:

warning: cast from 'const byte *' (aka 'const unsigned char *') to 'word64 *'
(aka 'unsigned long long *') increases required alignment from 1 to 8 [-Wcast-align]
    word64 tmp = *(word64 *)inBlock ^ roundKeys[0];
                  ^~~~~~~~~~~~~~~~~

使用Clang,我可以使用 assert 进行检测,编译器有时会将其作为诊断提示。但它似乎并不适用于这种情况。也就是说,Clang没有建立 assert(inBlock % 8 == 0); 意味着它已对齐的连接。

如何向编译器传达缓冲区是否对齐而不抑制警告?

2 个答案:

答案 0 :(得分:2)

这让Clang很开心,但会增加冗余计算(所以,对于发布版本来说可能不行):

uint64_t y = *(uint64_t *)((uintptr_t)x & ~7UL);

使用GCC,您可以使用__builtin_assume_aligned。引自GCC Manual

  

内置功能:

void * __builtin_assume_aligned (const void *exp, size_t align, ...)
     

此函数返回其第一个参数,并允许编译器执行   假设返回的指针至少对齐字节对齐。这个   内置的可以有两个或三个参数,如果它有三个,那么   第三个参数应该是整数类型,如果它是非零的意思   错位偏移。例如:

void *x = __builtin_assume_aligned (arg, 16);
     

表示编译器可以假设x设置为arg,至少是16字节对齐,而:

void *x = __builtin_assume_aligned (arg, 32, 8);
     

表示编译器可以假设x设置为arg(char *) x - 8require("script1.js")   32字节对齐。

LLVM还有patch来实现__builtin_assume_aligned,但尚未合并。英特尔编译器的类似内在函数exists。不确定Visual Studio。

答案 1 :(得分:2)

由于OP现有代码库不需要强类型匹配,因此简单地将大多数类型匹配与void*相匹配,这将使警告静音。参考文献@Ctx

 void DoSomethingWithBuffer(const byte* buff, size_t size) {
   const word64* ptr = (void*) buff;
   ...
 }