提前道歉,这可能是一个蹩脚的第一篇文章.虽然这个主题有很多材料,但对我来说很少是明确的和/或可理解的.
我有一个AlignedArray模板类,可以在堆上动态分配任意对齐的内存(我需要为AVX程序集例程进行32字节对齐).这需要一些丑陋的指针操作.
Agner Fog在cppexamples.zip中提供了一个样本类,它滥用了一个联合(http://www.agner.org/optimize/optimization_manuals.zip).但是,我知道写一个联盟的一个成员然后从另一个成员读取会导致UB.
AFAICT可以安全地将任何指针类型别名为a char *,但只能在一个方向上.这是我理解变得模糊的地方.这是我AlignedArray
课程的精简版(基本上是对Agner的重写,以帮助我理解):
template <typename T, size_t alignment = 32>
class AlignedArray
{
size_t m_size;
char * m_unaligned;
T * m_aligned;
public:
AlignedArray (size_t const size)
: m_size(0)
, m_unaligned(0)
, m_aligned(0)
{
this->size(size);
}
~AlignedArray ()
{
this->size(0);
}
T const & operator [] (size_t const i) const { return m_aligned[i]; }
T & operator [] (size_t const i) { return m_aligned[i]; }
size_t const size () { …Run Code Online (Sandbox Code Playgroud) 我的问题很简单;
alignas说明符是否与'new'一起使用?也就是说,如果一个struct定义为对齐,那么在分配new时它是否会对齐?
我知道gcc有一个选项-Wcast-align,只要指针被转换就会发出警告,以便增加目标所需的对齐.
这是我的计划:
char data[10];
int ptr = *((int *)data);
Run Code Online (Sandbox Code Playgroud)
在我的机器上,数据的对齐要求是1,而ptr是8.
为什么我没有收到警告?
可能是因为我正在为x86编译吗?
我在使用时遇到对齐问题 ymm寄存器,一些代码片段对我来说似乎很好.这是一个最小的工作示例:
#include <iostream>
#include <immintrin.h>
inline void ones(float *a)
{
__m256 out_aligned = _mm256_set1_ps(1.0f);
_mm256_store_ps(a,out_aligned);
}
int main()
{
size_t ss = 8;
float *a = new float[ss];
ones(a);
delete [] a;
std::cout << "All Good!" << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当然,sizeof(float)是4在我的架构(英特尔(R)至强(R)CPU E5-2650 V2 @ 2.60GHz),我与编译gcc使用-O3 -march=native标志.当然,错误会随着未对齐的内存访问而消失,即指定_mm256_storeu_ps.我在xmm寄存器上也没有这个问题,即
inline void ones_sse(float *a)
{
__m128 out_aligned = _mm_set1_ps(1.0f);
_mm_store_ps(a,out_aligned);
}
Run Code Online (Sandbox Code Playgroud)
我做了什么愚蠢的事吗?解决这个问题的方法是什么?
特别是在GCC上(也就是说,用GCC编译),以下两种方式有什么区别?
struct foo1 {
char a;
int b;
} __attribute__((__packed__, aligned(n) ));
Run Code Online (Sandbox Code Playgroud)
和:
#pragma pack(push, n)
struct foo2 {
char a;
int b;
};
#pragma pack(pop)
Run Code Online (Sandbox Code Playgroud)
它们看起来表现不同:
foo1 f1;
foo2 f2;
int& i1 = f1.b; // ok
int& i2 = f2.b; // cannot bind packed field 'f2.foo2::b' to 'int&'
Run Code Online (Sandbox Code Playgroud)
为什么一个而不是另一个有错误?内存布局至少相同吗?
我偶然发现了std::alignment_of类型特征,以及即将成为朋友的类型特征std::alignment_of_v.它们似乎专门设计为等同于普通调用alignof,并且未来添加_v帮助程序表明它不仅仅是遗留位.
有什么用的std::alignment_of(_v),当我们有alignof?
既然std::array不允许更改其分配器,是否有办法确保指向数据地址的指针是对齐的?
例如,在GNU g ++ 4.8.4和6.1.0中,代码如下
#include <array>
#include <iostream>
int main(void)
{
std::array<bool, 10> a;
std::array<char, 10> b;
std::array<int,10> c;
std::array<long long, 10> d;
std::array<float, 10> e;
std::array<double, 10> f;
std::cout << "array<bool,10>.data() = " << a.data() << std::endl;
std::cout << "array<char,10>.data() = " << (void*) b.data() << std::endl;
std::cout << "array<int,10>.data() = " << c.data() << std::endl;
std::cout << "array<long long, 10>.data() = " << d.data() << std::endl;
std::cout << "array<float, 10>.data() = " << e.data() << …Run Code Online (Sandbox Code Playgroud) 与我在C++中学到的相似,我认为填充会导致两个结构的实例大小不同.
type Foo struct {
w byte //1 byte
x byte //1 byte
y uint64 //8 bytes
}
type Bar struct {
x byte //1 byte
y uint64 //8 bytes
w byte// 1 byte
}
func main() {
fmt.Println(runtime.GOARCH)
newFoo := new(Foo)
fmt.Println(unsafe.Sizeof(*newFoo))
newBar := new(Bar)
fmt.Println(unsafe.Sizeof(*newBar))
}
Run Code Online (Sandbox Code Playgroud)
输出:
amd64
16
24
Run Code Online (Sandbox Code Playgroud)
当浏览operator new、operator new[] - cppreference.com时,我们似乎有很多选项来分配具有特定对齐要求的对象数组。但是,没有指定如何使用它们,而且我似乎找不到正确的 C++ 语法。
我可以以某种方式显式调用该运算符,还是编译器会自动推断重载?:
void* operator new[]( std::size_t count, std::align_val_t al );
Run Code Online (Sandbox Code Playgroud)
看看Bartek的编码博客,似乎编译器会根据对齐要求是否大于__STDCPP_DEFAULT_NEW_ALIGNMENT__(在64位机器上通常为16)自动选择重载。
在某些情况下是否可以手动为new操作员选择重载?有时我可能希望分配的块以某种方式对齐(我假设对齐始终是 2 的幂,并且可能大于 16)。
在可预见的将来,我可能会使用 GCC 和 C++ >= 17。
我试图理解为什么只包含 int 的结构在类中占用 8 个字节的内存。
考虑以下代码;
static void Main()
{
var rand = new Random();
var twoIntStruct = new TwoStruct(new IntStruct(rand.Next()), new IntStruct(rand.Next()));
var twoInt = new TwoInt(rand.Next(), rand.Next());
Console.ReadLine();
}
public readonly struct IntStruct
{
public int Value { get; }
internal IntStruct(int value)
{
Value = value;
}
}
public class TwoStruct
{
private readonly IntStruct A;
private readonly IntStruct B;
public TwoStruct(
IntStruct a,
IntStruct b)
{
A = a;
B = b;
}
}
public class …Run Code Online (Sandbox Code Playgroud)