微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何对齐指针

如何解决如何对齐指针

| 如何将指针对准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 举报,一经查实,本站将立刻删除。