指针对齐的正确方法
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.
的练习。
我有以下指针对齐代码
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.
的练习。