指针对齐的正确方法

Correct way for pointer alignment

我有以下指针对齐代码

char *p = new char[1000];
//...
++p;
//...
int alignment = 4;
int extra_bytes = (size_t)p % alignment;

int *aligned_ptr = (int*)(p + (alignment - extra_bytes));
std::cout << ((size_t)aligned_ptr % alignment); //aligned
//... 

我想知道它是指针对齐的正确代码吗?如果是,这里的任何人都可以展示哪个更好的实现吗? (例如,使用位运算)

如果在执行 modulo 运算后您的商为 0,则指针已对齐 指针 mod 对齐.

这意味着您可以使用

检查(在 C++11 中)
#include <cstdint>
bool isAligned = ((reinterpret_cast<std::uintptr_t>(pointer) % alignment) == 0);

您也可以使用按位运算(仅当对齐是 2 的幂时)

bool isAligned = ((reinterpret_cast<std::uintptr_t>(pointer) & (alignment - 1)) == 0);

但是,编译器可能会为您优化它。

通常,您实际上不需要强制转换指针来检查其位,因为您可以使用缓冲区内的索引。考虑使用类似的东西:

#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <stdexcept>
#include <vector>

// in case your compiler doesn't support C++11 `alignof`,
// it's easy to implement
#define ALIGNOF(T) (sizeof(alignof_helper<T>) - sizeof(T))
// or in GNU C, although it provides __alignof__ anyway
#define ALIGNOF_C(T) ({ struct alignof_c_helper { char c; T data; }; sizeof(alignof_c_helper) - sizeof(T); })
// but of course, macros are EVIL.
template<class T>
struct alignof_helper
{
    char c;
    // implicit padding since data must be aligned
    T data;
};

struct aligned_buffer
{
    std::vector<uint8_t> vec;
    size_t index;

    aligned_buffer(size_t sz = 0)
    : vec(sz)
    , index(0)
    {
    }

    template<class T>
    T *get(size_t count=1)
    {
        // malloc() and ::operator new() return normally-aligned memory
        static_assert(alignof(T) <= alignof(std::max_align_t), "no overaligned types without a special allocator");
        size_t offset = this->index % alignof(T);
        size_t start_index = this->index;
        size_t new_index, asize;
        if (offset)
        {
            start_index += alignof(T) - offset;
            if (!start_index) // overflowed
                throw std::length_error("how did you allocate that much? I'm impressed");
        }
        if (__builtin_mul_overflow(alignof(T), count, &asize) || __builtin_add_overflow(start_index, asize, &new_index))
        {
            throw std::length_error("ridiculous size");
        }
        if (new_index > this->vec.size())
        {
            throw std::length_error("insufficient reserved space");
        }
        this->index = new_index;
        return reinterpret_cast<T *>(&this->vec[start_index]);
    }
};

int main()
{
    static_assert(alignof(int) == ALIGNOF(int), "C++98 version");
    static_assert(alignof(int) == ALIGNOF_C(int), "GNU C statement-expression");
    static_assert(alignof(int) == __alignof__(int), "GNU C keyword");

    static_assert(alignof(int) == 4 && alignof(long long) == 8, "tests below assume a \"normal\" environment");
    aligned_buffer buf(16);
    *buf.get<char>() = 'A';
    auto a = buf.get<int>(2);
    a[0] = 123;
    a[1] = 456;
    try
    {
        buf.get<long long>();
        throw std::logic_error("code is wrong I guess?");
    }
    catch (std::length_error& e)
    {
    }
    // can still use the buffer
    *buf.get<char>() = 'Z';

    puts("everything is okay");
}

修改此代码以允许安全地调整底层缓冲区的大小,从而担心指针失效,留作 reader.

的练习。