如何解决如何对齐指针
| 如何将指针对准16字节边界? 我找到了此代码,不确定其是否正确char* p= malloc(1024);
if ((((unsigned long) p) % 16) != 0)
{
unsigned char *chpoint = (unsigned char *)p;
chpoint += 16 - (((unsigned long) p) % 16);
p = (char *)chpoint;
}
这行得通吗?
谢谢
解决方法
C ++ 0x提出了
std::align
,它就是这样做的。
// get some memory
T* const p = ...;
std::size_t const size = ...;
void* start = p;
std::size_t space = size;
void* aligned = std::align(16,1024,p,space);
if(aligned == nullptr) {
// failed to align
} else {
// here,p is aligned to 16 and points to at least 1024 bytes of memory
// also p == aligned
// size - space is the amount of bytes used for alignment
}
这似乎很底层。我认为
// also available in Boost flavour
using storage = std::aligned_storage_t<1024,16>;
auto p = new storage;
也可以。即使您不小心,也可以轻易地使用别名规则。如果您有一个精确的场景(在16个字节的边界处适合N个类型为T的对象?)我想我可以推荐一些更好的方法。
, 尝试这个:
它返回对齐的内存并释放内存,几乎没有额外的内存管理开销。
#include <malloc.h>
#include <assert.h>
size_t roundUp(size_t a,size_t b) { return (1 + (a - 1) / b) * b; }
// we assume here that size_t and void* can be converted to each other
void *malloc_aligned(size_t size,size_t align = sizeof(void*))
{
assert(align % sizeof(size_t) == 0);
assert(sizeof(void*) == sizeof(size_t)); // not sure if needed,but whatever
void *p = malloc(size + 2 * align); // allocate with enough room to store the size
if (p != NULL)
{
size_t base = (size_t)p;
p = (char*)roundUp(base,align) + align; // align & make room for storing the size
((size_t*)p)[-1] = (size_t)p - base; // store the size before the block
}
return p;
}
void free_aligned(void *p) { free(p != NULL ? (char*)p - ((size_t*)p)[-1] : p); }
警告:
我很确定我会在这里使用C标准的某些部分,但谁在乎呢。 :P
, 在glibc库malloc
中,realloc
始终返回8个字节对齐。如果要以较高的幂2对齐方式分配内存,则可以使用memalign
和posix_memalign
。阅读http://www.gnu.org/s/hello/manual/libc/Aligned-Memory-Blocks.html
, posix_memalign是一种方法:http://pubs.opengroup.org/onlinepubs/009695399/functions/posix_memalign.html,只要您的大小是2的幂。
您提供的解决方案的问题在于,您有可能注销已分配内存的末尾。另一种解决方案是分配您想要的大小+ 16,并使用与您正在使用的技巧类似的技巧来获得对齐的指针,但该指针仍在分配的区域内。就是说,我将使用posix_memalign作为第一个解决方案。
, 一些事情:
不要更改malloc / new返回的指针:稍后将需要它来释放内存;
调整对齐方式后,确保缓冲区足够大
使用size_t
而不是unsigned long
,因为size_t
保证与指针具有相同的大小,而不是其他任何东西:
这是代码:
size_t size = 1024; // this is how many bytes you need in the aligned buffer
size_t align = 16; // this is the alignment boundary
char *p = (char*)malloc(size + align); // see second point above
char *aligned_p = (char*)((size_t)p + (align - (size_t)p % align));
// use the aligned_p here
// ...
// when you\'re done,call:
free(p); // see first point above
, 更新:更快的新算法
不要使用模数,因为由于令人讨厌的划分,在x86上需要花费数百个时钟周期,而在其他系统上则需要更多时间。我想出了比GCC和Visual-C ++更快的std :: align版本。 Visual C ++具有最慢的实现,实际上使用业余条件语句。 GCC与我的算法非常相似,但是我做了相反的事情,但是我的算法快了13.3%,因为它有13条指令,而不是15条单周期指令。请参阅此处为可拆卸的研究论文。如果使用掩码而不是pow_2,则该算法实际上快了一条指令。
/* Quickly aligns the given pointer to a power of two boundaries.
@return An aligned pointer of typename T.
@desc Algorithm is a 2\'s compliment trick that works by masking off
the desired number in 2\'s compliment and adding them to the
pointer. Please note how I took the horizontal comment whitespace back.
@param pointer The pointer to align.
@param mask Mask for the lower LSb,which is one less than the power of
2 you wish to align too. */
template <typename T = char>
inline T* AlignUp(void* pointer,uintptr_t mask) {
intptr_t value = reinterpret_cast<intptr_t>(pointer);
value += (-value) & mask;
return reinterpret_cast<T*>(value);
}
这是你的称呼:
enum { kSize = 256 };
char buffer[kSize + 16];
char* aligned_to_16_byte_boundary = AlignUp<> (buffer,15); //< 16 - 1 = 15
char16_t* aligned_to_64_byte_boundary = AlignUp<char16_t> (buffer,63);
这是3位的快速按位证明,所有位计数的作用相同:
~000 = 111 => 000 + 111 + 1 = 0x1000
~001 = 110 => 001 + 110 + 1 = 0x1000
~010 = 101 => 010 + 101 + 1 = 0x1000
~011 = 100 => 011 + 100 + 1 = 0x1000
~100 = 011 => 100 + 011 + 1 = 0x1000
~101 = 010 => 101 + 010 + 1 = 0x1000
~110 = 001 => 110 + 001 + 1 = 0x1000
~111 = 000 => 111 + 000 + 1 = 0x1000
万一您在这里学习如何在C ++ 11中将对象对齐到高速缓存行,请使用就地构造函数:
struct Foo { Foo () {} };
Foo* foo = new (AlignUp<Foo> (buffer,63)) Foo ();
这是std :: align实现,它使用24条指令,而GCC实现使用31条指令,尽管可以通过将最低有效位的(--align)
转换为mask
进行调整以消除减量指令,但其功能与std :: align。
inline void* align(size_t align,size_t size,void*& ptr,size_t& space) noexcept {
intptr_t int_ptr = reinterpret_cast<intptr_t>(ptr),offset = (-int_ptr) & (--align);
if ((space -= offset) < size) {
space += offset;
return nullptr;
}
return reinterpret_cast<void*>(int_ptr + offset);
}
更快使用面膜,而不是pow_2
这是用于使用遮罩而不是pow_2(这是2的偶数幂)进行对齐的代码。这比GCC算法胖20%,但要求您存储掩码而不是pow_2,因此它不可互换。
inline void* AlignMask(size_t mask,offset = (-int_ptr) & mask;
if ((space -= offset) < size) {
space += offset;
return nullptr;
}
return reinterpret_cast<void*>(int_ptr + offset);
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。