场景
1.在使用一些相关原子操作的函数或指令时, 一般都需要对操作的变量地址进行对齐, 4,8,16…字节对齐.
2.在没有引入C++11的alignas指示符之前, 一般都是使用
__declspec(align(4)) int i; // Windows
alignas(4) int j; // C++
或定义一些存储空间进行计算转换, 参考数据地址对齐. 不同的是前者是编译时刻计算出地址,后者是运行时刻计算出内存对齐地址; 麻烦的是VS2010 并不是完整支持C++11对齐特性.
说明
1.C++11 引入了很多地址对齐相关的操作符, 函数, 模板。
alignas 说明符
1.同Windows的 __declspec(align(4))
, VS2010不支持alignas 和 align(int)语法. 作用就是在编译时期分配对齐地址.
alignas( expression ) // alignas(4)
alignas( type-id ) // alignas(int)
alignof 操作符,alignment_of 类模板
1.他们是计算某个类型的对齐需要的字节数, 目前发现他们的值是一样的. 唯一不同的是前者是编译时计算,可用于模板,后者是运行时计算。
alignof( type-id )
#include <type_traits>
template< class T >
struct alignment_of;
std::align 函数
1.和数据地址对齐里介绍的APR_ALIGN对齐一样, 用于运行时计算内存对齐存储地址. 可惜 VS2010 没有 std::align函数.
#include <memory>
void* align( std::size_t alignment,
std::size_t size,
void*& ptr,
std::size_t& space );
std::aligned_storage 类模板
- 用于创建对齐静态数组, 即创建的数组里元素都是指定字节对齐的.
#include <type_traits>
template< std::size_t Len, std::size_t Align = /*default-alignment*/ >
struct aligned_storage;
例子
1.这里只是部分例子, 详细的说明符, 模板, 函数使用参考对应的链接.
#include <regex>
#include <assert.h>
#include <iostream>
#include <utility>
#include <stdint.h>
#include <iterator>
#include <set>
#include <typeinfO>
#include <iomanip>
#include <type_traits>
template<class _Ty>
struct _Get_align
{ // struct used to determine alignemt of _Ty
_Ty _Elt0;
char _Elt1;
_Ty _Elt2;
};
#define _ALIGN_OF(ty) (sizeof(_Get_align<ty>) - 2 *sizeof(ty))
// Apache
/* APR_ALIGN() is only to be used to align on a power of 2 boundary */
#define APR_ALIGN(size1, boundary) (((size1) + ((boundary) - 1)) & ~((boundary) - 1))
void TestAlign()
{
int size1 = std::alignment_of<int64_t>().value;
int size2 = _ALIGN_OF(int64_t);
//1. 32字节对齐. 数值地址.要对齐地址,一般会创建多出的空间来对齐.
//1. 需要创建16字节空间,如果需要32字节对齐.
uint8_t* value = (uint8_t*)malloc(16+32);
std::cout <<"1 " << (int64_t)(int64_t*)(value) << std::endl;
int64_t* value_offset = (int64_t*)APR_ALIGN((int64_t)(int64_t*)value,32);
std::cout <<"2 " << (int64_t)(int64_t*)(value_offset) << std::endl;
__declspec(align(32)) char buf[16] = {0}; // 如果去掉 align, assert基本上都会崩溃.
assert(((int64_t)(void*)buf % 32) == 0);
std::cout << (void*)buf << std::endl;
}
输出:
1 6981544
2 6981568
0039F740
参考
aligned_storage
align Windows
alignment_of
align
aligned_union
Alignment
alignas
parameter_pack
数据地址对齐
原子操作1