查找下一个对齐的内存地址

Find next aligned memory address

本文关键字:内存 地址 对齐 下一个 查找      更新时间:2023-10-16

根据我对维基百科的理解,我可以通过以下按位运算找到下一个最接近元素的索引,并正确对齐。

Assuming the address of the 1st element has the correct alignment.
Assuming the index_alignment is a power of 2.
new_index = (current_index + index_alignment - 1) & ~(index_alignment - 1).
new_address = address_of_1st_element + new_index
index_alignment is 16 bytes/sizeof(type of element) for SSE.

是否可以直接在地址上使用它来从任何给定地址中找到下一个最接近的对齐地址?(这样更快吗?

我正在考虑以下几点以快速完成此操作。

new_address = (current_address + alignment - 1) & ~(alignment -1)
alignment here is 16 for SSE.

当我实现这个时,我发现下面的代码无法编译...

使用Salva和Rotem的建议修复的代码

#include <iostream>
#include <stdint.h>
#define ALIGNMENT 16
using namespace std;
uint32_t* fix_ptr(uint32_t* ptr){
    return (uint32_t*)(
        (uintptr_t(ptr) + uintptr_t(ALIGNMENT) - 1)
        &~ uintptr_t(ALIGNMENT - 1)
        );
}
void print_ptr (uint32_t* ptr){
    cout << (long long)(void*)ptr << endl;
}
void test(uintptr_t ptr_as_int){
    uint32_t* ptr1 = (uint32_t*) ptr_as_int;
    cout << "Initial address: ";
    print_ptr(ptr1);
    uintptr_t alignment = ALIGNMENT;
    cout << "    alignment: " << alignment << endl;
    cout << "    alignment - 1: " << (alignment - 1) << endl;
    cout << "    alignment & alignment: " << (alignment & alignment) << endl;
    uint32_t* ptr_fixed = fix_ptr(ptr1);
    cout << "    fixed address: ";
    print_ptr(ptr_fixed);
}
int main(void){
    test(1000);
    test(16);
}

输出(使用 g++ 代码编译.cpp)

Initial address: 1000
    alignment: 16
    alignment - 1: 15
    alignment & alignment: 16
    fixed address: 1008
Initial address: 16
    alignment: 16
    alignment - 1: 15
    alignment & alignment: 16
    fixed address: 16

1000 按预期变为 1008,16 变为 16。对于我目前的使用来说可能还可以。不知道有没有更快的方法。

谢谢。

自 C++11 年以来,C++ 标准库中的 memory 标头中具有执行此操作的 std::align 函数。至少在GNU实现(libstdc++)中,std::align执行与OP几乎相同的位操作:

const auto __aligned = (__intptr - 1u + __align) & -__align;

除了第一个-1的位置之外,唯一的区别是它使用-__align而不是~(__align - 1),因为两者是等价的。

std::align 还接受一个size和一个space参数,并检查在正确对齐后给定的类型是否仍然适合给定的缓冲区/分配space,以及从space参数(引用)中减去用于对齐的字节。

以下是没有这些检查的版本,以及仅检查所需的其他参数。

#include <cstddef>
#include <cstdint>
inline void *align(std::size_t alignment, void *ptr) noexcept {
    const auto intptr = reinterpret_cast<std::uintptr_t>(ptr);
    const auto aligned = (intptr - 1u + alignment) & -alignment;
    return reinterpret_cast<void *>(aligned);
}