如何确定内存是否alignment? (*testing*alignment,不alignment)

我是新来的优化代码SSE / SSE2指示,直到现在我还没有得到很远。 据我所知,一个通用的SSE优化函数看起来像这样:

void sse_func(const float* const ptr, int len){ if( ptr is aligned ) { for( ... ){ // unroll loop by 4 or 2 elements } for( ....){ // handle the rest // (non-optimized code) } } else { for( ....){ // regular C code to handle non-aligned memory } } } 

但是,如何正确确定内存ptr指向例如16字节? 我想我必须包括非alignment内存的常规C代码path,因为我不能确保传递给这个函数的每个内存将被alignment。 使用内部函数将未alignment内存中的数据加载到SSE寄存器中似乎是非常慢(甚至比普通C代码慢)。

先谢谢你…

编辑:铸造到long是一种廉价的方法来保护自己最有可能的可能性int和指针是不同大小的时下。

正如在下面的评论中指出的,如果你愿意包含头文件,那么有更好的解决scheme。

指针p在16字节的边界上alignmentiff ((unsigned long)p & 15) == 0

 #define is_aligned(POINTER, BYTE_COUNT) \ (((uintptr_t)(const void *)(POINTER)) % (BYTE_COUNT) == 0) 

void * (或等价的, char * )进行uintptr_t转换是必要的,因为该标准只保证对void * uintptr_t进行可逆转换。

如果您想要types安全,请考虑使用内联函数:

 static inline _Bool is_aligned(const void *restrict pointer, size_t byte_count) { return (uintptr_t)pointer % byte_count == 0; } 

并希望编译器优化,如果byte_count是一个编译时常量。

为什么我们需要转换为 void *

C语言允许对不同的指针types进行不同的表示,例如,你可以有一个64位的void *types(整个地址空间)和一个32位的foo *types(一个段)。

转换foo * – > void *可能涉及实际计算,例如添加偏移量。 这个标准还将实现什么时候将(任意)指针转换为整数,但我怀疑它通常是作为一个noop实现的。

对于这样的实现, foo * – > uintptr_t – > foo *可以工作,但是foo * – > uintptr_t – > void *void * – > uintptr_t – > foo *不会。 alignment计算也不能可靠地工作,因为你只检查alignment相对于段偏移量,这可能或可能不是你想要的。

总之:总是使用void *来获得独立于实现的行为。

其他答案build议设置低位的AND运算,并将其与零进行比较。

但是更直接的testing是做一个具有所需alignment值的MOD,并将其与零比较。

 #define ALIGNMENT_VALUE 16u if (((uintptr_t)ptr % ALIGNMENT_VALUE) == 0) { // ptr is aligned } 

用一个类似的函数模板

 #include <type_traits> template< typename T > bool is_aligned(T* p){ return !(reinterpret_cast<uintptr_t>(p) % std::alignment_of<T>::value); } 

你可以通过调用类似的东西在运行时检查alignment

 struct foo_type{ int bar; }foo; assert(is_aligned(&foo)); // passes 

要检查不好的路线失败,你可以做

 // would almost certainly fail assert(is_aligned((foo_type*)(1 + (uintptr_t)(&foo))); 

你可以'和'与0x03(4salignment),0x07(8salignment)或0x0f(16salignment)的ptr,看是否有最低位设置?

这基本上是我用的。 通过使整型成为一个模板,我确保它扩展了编译时间,所以不pipe我做什么,我都不会得到一个缓慢的模运算。

我总是喜欢检查我的input,所以编译时间断言。 如果你的alignment值是错误的,那么它不会编译…

 template <unsigned int alignment> struct IsAligned { static_assert((alignment & (alignment - 1)) == 0, "Alignment must be a power of 2"); static inline bool Value(const void * ptr) { return (((uintptr_t)ptr) & (alignment - 1)) == 0; } }; 

要看看发生了什么,你可以使用这个:

 // 1 of them is aligned... int* ptr = new int[8]; for (int i = 0; i < 8; ++i) std::cout << IsAligned<32>::Value(ptr + i) << std::endl; // Should give '1' int* ptr2 = (int*)_aligned_malloc(32, 32); std::cout << IsAligned<32>::Value(ptr2) << std::endl; 

怎么样:

 void *mem = malloc(1024+15); void *ptr =( (*(char*)mem) - (*(char *)mem % 16) );