在不抑制警告的情况下告诉编译器对齐可以的便携式方法?
Portable way to tell the compiler that alignment is OK without supressing the warning?
我们 运行 的测试之一是使用 -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);
表示其对齐。
如何在不抑制警告的情况下向编译器传达缓冲区已对齐?
这让 Clang 很高兴,但会增加冗余计算(因此,它可能不适用于发布版本):
uint64_t y = *(uint64_t *)((uintptr_t)x & ~7UL);
通过 GCC,您可以使用 __builtin_assume_aligned
。引自 GCC Manual:
Built-in Function:
void * __builtin_assume_aligned (const void *exp, size_t align, ...)
This function returns its first argument, and allows the compiler to
assume that the returned pointer is at least align bytes aligned. This
built-in can have either two or three arguments, if it has three, the
third argument should have integer type, and if it is nonzero means
misalignment offset. For example:
void *x = __builtin_assume_aligned (arg, 16);
means that the compiler can assume x
, set to arg
, is at least 16-byte aligned, while:
void *x = __builtin_assume_aligned (arg, 32, 8);
means that the compiler can assume for x
, set to arg
, that (char *) x - 8
is
32-byte aligned.
还有一个用于英特尔编译器的 patch for LLVM to implement __builtin_assume_aligned, but it has not been merged yet. Similar intrinsic function exists。不确定 Visual Studio。
由于 OP 现有代码库不需要强类型匹配,使用 void*
可以简单地击败大多数类型匹配,这将消除警告。也参考
void DoSomethingWithBuffer(const byte* buff, size_t size) {
const word64* ptr = (void*) buff;
...
}
我们 运行 的测试之一是使用 -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);
表示其对齐。
如何在不抑制警告的情况下向编译器传达缓冲区已对齐?
这让 Clang 很高兴,但会增加冗余计算(因此,它可能不适用于发布版本):
uint64_t y = *(uint64_t *)((uintptr_t)x & ~7UL);
通过 GCC,您可以使用 __builtin_assume_aligned
。引自 GCC Manual:
Built-in Function:
void * __builtin_assume_aligned (const void *exp, size_t align, ...)
This function returns its first argument, and allows the compiler to assume that the returned pointer is at least align bytes aligned. This built-in can have either two or three arguments, if it has three, the third argument should have integer type, and if it is nonzero means misalignment offset. For example:
void *x = __builtin_assume_aligned (arg, 16);
means that the compiler can assume
x
, set toarg
, is at least 16-byte aligned, while:void *x = __builtin_assume_aligned (arg, 32, 8);
means that the compiler can assume for
x
, set toarg
, that(char *) x - 8
is 32-byte aligned.
还有一个用于英特尔编译器的 patch for LLVM to implement __builtin_assume_aligned, but it has not been merged yet. Similar intrinsic function exists。不确定 Visual Studio。
由于 OP 现有代码库不需要强类型匹配,使用 void*
可以简单地击败大多数类型匹配,这将消除警告。也参考
void DoSomethingWithBuffer(const byte* buff, size_t size) {
const word64* ptr = (void*) buff;
...
}