我在Cell处理器上调整DMA传输的内存时遇到问题.我需要地址的最后4位为0.
我有4个数组,unsigned int其中每个元素必须在内存中对齐,以便其(十六进制)地址以零结尾.
例如
int main()
{
size_t i;
static unsigned int a[2] __attribute__ ((aligned (16)));
static unsigned int b[2] __attribute__ ((aligned (16)));
static unsigned int c[2] __attribute__ ((aligned (16)));
static unsigned int d[2] __attribute__ ((aligned (16)));
for (i = 0; i < 2; ++i) {
printf("a[%u] = %p\n", &a[i]);
printf("b[%u] = %p\n", &b[i]);
printf("c[%u] = %p\n", &c[i]);
printf("d[%u] = %p\n", &d[i]);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
a[0] = 0x10010b60
b[0] = 0x10010b50
c[0] = 0x10010b40 …Run Code Online (Sandbox Code Playgroud) 在C ++中,至少在GCC和Clang上,嵌入在容器(std :: vector)中的超对齐类型似乎被不同地对待,具体取决于该类型是超对齐结构还是超对齐枚举。对于struct版本,每个元素都对齐,而对于枚举,只有整个缓冲区具有指定的对齐方式。该行为是否由标准指定?如果是这样,哪一部分提到了?还是实现定义的,不应该依赖?
考虑以下:
#include<cstdint>
#include<iostream>
#include<vector>
struct alignas(16) byte_struct {std::uint8_t value;};
enum alignas(16) byte_enum : std::uint8_t {};
int main() {
{//with struct
std::vector<byte_struct> bytes;
bytes.push_back(byte_struct{1});
bytes.push_back(byte_struct{2});
bytes.push_back(byte_struct{3});
for(auto it = bytes.begin(); it!= bytes.end(); ++it) {
std::cout<<&*it<<std::endl;
}
}
{//with enum
std::vector<byte_enum> bytes;
bytes.push_back(byte_enum{1});
bytes.push_back(byte_enum{2});
bytes.push_back(byte_enum{3});
for(auto it = bytes.begin(); it!= bytes.end(); ++it) {
std::cout<<&*it<<std::endl;
}
}
}
Run Code Online (Sandbox Code Playgroud)
具有过度对齐的结构的版本将打印以下内容
0x10a9ec0 0x10a9ed0 0x10a9ee0
带有过度对齐的枚举的版本将打印以下内容
0x10a9e70 0x10a9e71 0x10a9e72
在向量存储区中,每个byte_struct都对齐到16个字节的边界,而byte_enum的对齐方式只适用于整个缓冲区,而不适用于每个单独的元素。
在GCC 9.1和Clang 8.0上,此行为相同,而MSVC 19.20遇到内部编译器错误。
编译器资源管理器的链接为:https : //godbolt.org/z/GUg2ft
假设这段代码:
unsigned char list[3] = { 1, 2, 3 };
struct _struct{
unsigned char a;
unsigned char b;
unsigned char c;
} *s;
s = ( _struct * ) list; Run Code Online (Sandbox Code Playgroud)
我能一直假设s->a == 1, s->b == 2, s->c == 3吗?
或者它将取决于系统的字节顺序或内存对齐?
假设有类似的东西:
void mask_bytes(unsigned char* dest, unsigned char* src, unsigned char* mask, unsigned int len)
{
unsigned int i;
for(i=0; i<len; i++)
{
dest[i] = src[i] & mask[i];
}
}
Run Code Online (Sandbox Code Playgroud)
通过编写类似下面的内容,我可以更快地在非对齐访问机器(例如x86)上运行
void mask_bytes(unsigned char* dest, unsigned char* src, unsigned char* mask, unsigned int len)
{
unsigned int i;
unsigned int wordlen = len >> 2;
for(i=0; i<wordlen; i++)
{
((uint32_t*)dest)[i] = ((uint32_t*)src)[i] & ((uint32_t*)mask)[i]; // this raises SIGBUS on SPARC and other archs that require aligned access.
}
for(i=wordlen<<2; i<len; i++){ …Run Code Online (Sandbox Code Playgroud) 是否valarray有连续的内存对齐?
我想将一个valarray传递给一个函数(来自IPPS),它只通过传递来获取指针&myValarray[0].但是我应该确定,valarray的内存对齐是连续的.
谢谢!
C#规范(ECMA-334和ISO/IEC 23270)有一段关于读写的原子性:
12.5变量引用的原子性
以下数据类型的读取和写入应为原子:bool,char,byte,sbyte,short,ushort,uint,int,float和reference类型.此外,在先前列表中具有基础类型的枚举类型的读取和写入也应该是原子的.其他类型的读写,包括long,ulong,double和decimal,以及用户定义的类型,不一定是原子的.
但我很难想象永远是真的.例如,我可以使用StructLayout属性布局结构,并强制字段不对齐:
// sizeof(MyStruct) == 9
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct MyStruct
{
public byte pad; // Offset: 0
public int value1; // Offset: 1
public int value2; // Offset: 5
}
Run Code Online (Sandbox Code Playgroud)
现在,当我这样做,我会觉得写的int是不是原子的,因为它没有对齐的自然边界:
MyStruct myStruct = new MyStruct();
myStruct.value1 = 20;
Run Code Online (Sandbox Code Playgroud)
那么,它是绝对原子的(就像规范所说的那样),还是不能保证是原子的(例如在x86上)?无论哪种方式,你有任何消息来支持这个吗?
我最近修复了一个错误,其中一个__declspec(align(64))结构的成员由于分配结构的内存的方式而未对齐.所以,我正在寻找解决这种情况的方法.
例如,请考虑以下结构:
struct foo {
__declspec(align(64)) int bar[BAZ_LEN];
int baz;
};
Run Code Online (Sandbox Code Playgroud)
如果在堆栈上分配,编译器将负责对齐.如果通过分配malloc(),它将无法工作.如果出于性能或正确性原因(或两者)依赖于其对齐,这将破坏访问bar的代码.
所以,问题是:处理这种情况的最佳方法是什么?在我的情况下struct foo,除了我的组件的"私有"函数之外的所有函数都可以认为是不透明的.
澄清/更新.非常感谢你的答案.我应该事先说过这个问题,但问题是我的struct的用户分配了一大块内存并将其分成多个部分,其中一个中间部分是一个foo_tstructus 数组.该数组的偏移量不是常数,因此对齐起始地址可能没有帮助.我正在寻找一种方法来允许这样使用我的结构,同时保留一些对齐假设.
我现在想到的解决方案(还没试过这个)是添加一个填充成员:
struct foo {
__declspec(align(64)) int bar[BAZ_LEN];
int baz;
char padding[64];
};
Run Code Online (Sandbox Code Playgroud)
并且在每个函数中执行以下操作(包装在宏中):
void f(foo_t *foo_)
{
foo_t *foo = (foo_t *)(((uintptr_t)foo_ & ~63) + 64);
...
}
Run Code Online (Sandbox Code Playgroud)
这会浪费每个结构64个字节,这在我的情况下不是问题.由于从不访问填充成员,因此移位不会导致任何段错误.然而,这个解决方案增加了相当多的心理开销,因为必须为每个公共函数清理对齐...
当std::aligned_storage<2, 4096>::type在堆上分配一个时,我总是得到一个偏移16个字节的指针(在x64上;在x86上,它偏移8个字节).换句话说,这个:
#include <iostream>
#include <cstddef>
int main() {
typedef std::aligned_storage<2, 4096>::type MemPage;
MemPage* p_mp = new MemPage;
std::cout << (void*)p_mp << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
给我(例如)
0x72f010
Run Code Online (Sandbox Code Playgroud)
虽然我希望最后三位数都为零.在std::aligned_storage<>::type堆栈上分配时,一切都按预期工作.
我在ubuntu 14.04上使用gcc-4.8.2 x86_64.
我试图创建一个智能指针,它只有一个指向内存块的指针,该指针以引用计数器(控制块)开头,并在其后立即存储一个值。在从论坛、标准和 cppreference 中阅读了一些内容后,我意识到代码看起来充满了 UB。
#include <iostream>
#include <memory>
#include <type_traits>
#include <new>
struct alignas(alignof(size_t)) StorageBase {
size_t m_rc = 0;
};
template<typename T>
struct Storage: public StorageBase {
using value_type = T;
std::aligned_storage_t<sizeof(value_type), alignof(value_type)> m_value_storage;
};
class Dummy {
public:
Dummy() { std:: cout << "Dummy constructed" << std::endl; }
virtual ~Dummy() { std:: cout << "Dummy destructed" << std::endl; }
};
class DerivedDummy: public Dummy {
public:
DerivedDummy() { std:: cout << "DerivedDummy constructed" << std::endl; …Run Code Online (Sandbox Code Playgroud) 我正在研究对齐检查的问题。但我不知道处理器是在检查有效地址、线性地址还是物理地址,还是所有检查。
比如一个数据的有效地址已经对齐,但是加上段描述符的基地址形成的线性地址不再对齐,此时处理器抛出#AC异常。