我们运行的测试之一是使用-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);
意味着它已对齐的连接。
如何向编译器传达缓冲区是否对齐而不抑制警告?
答案 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 - 8
是require("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;
...
}