标签: memory-alignment

了解堆栈分配和对齐

我试图理解堆栈对齐是如何工作的,如什么是"堆栈对齐"?但我很难得到一个小例子来证明上述行为.我正在检查我的函数foo的堆栈分配:

void foo() {
    int a = 0;
    char b[16];
    b[0] = 'a';
}
Run Code Online (Sandbox Code Playgroud)

我编译了源文件gcc -ggdb example.c -o example.out(即没有任何编译器标志),并且gdb中的汇编器转储读取:

(gdb) disassemble foo
Dump of assembler code for function foo:
0x08048394 <+0>:    push   %ebp
0x08048395 <+1>:    mov    %esp,%ebp
0x08048397 <+3>:    sub    $0x20,%esp
0x0804839a <+6>:    movl   $0x0,-0x4(%ebp)
0x080483a1 <+13>:   movb   $0x61,-0x14(%ebp)
0x080483a5 <+17>:   leave  
0x080483a6 <+18>:   ret    
End of assembler dump.
Run Code Online (Sandbox Code Playgroud)

我的堆栈以16字节的块分配(我通过其他几个测试验证了这一点).根据汇编程序转储,这里分配了32个字节,因为(16 <4 + 16 <32),但我希望在前16个字节上分配整数'a',然后在接下来的16个字节上分配字符数组(在中间留下12个字节的空间).但似乎整数和字符数组都被分配了一个20字节的连续块,根据我上面提到的讨论,这是低效的.有人可以解释我在这里缺少的东西吗?

编辑:我得出结论,我的堆栈分配16个字节的块,使用如下程序:

void foo() {
    char a[1];
}
Run Code Online (Sandbox Code Playgroud)

和相应的汇编程序转储:

(gdb) disassemble foo …
Run Code Online (Sandbox Code Playgroud)

c stack memory-management memory-alignment

7
推荐指数
1
解决办法
5311
查看次数

未对齐数据的操作速度

据我所知,CPU在边界上对齐的数据表现最佳,该边界等于该数据的大小.例如,如果每个int数据的大小为4个字节,则每个数据的地址int必须是4的倍数才能使CPU满意; 与2字节short数据和8字节double数据相同.因此,new运算符和malloc函数始终返回8的倍数的地址,因此是4和2的倍数.

在我的程序中,一些用于处理大字节数组的时间关键算法允许通过将每个连续的4个字节转换为a来跨越计算,unsigned int并且以这种方式,更快地进行算术运算.但是,字节数组的地址不能保证是4的倍数,因为只需要处理字节数组的一部分.

据我所知,英特尔CPU正确处理未对齐的数据,但代价是速度.如果对未对齐的数据进行操作的速度足够慢,则需要重新设计程序中的算法.在这方面,我有两个问题,第一个问题支持以下代码:

// the address of array0 is a multiple of 4:
unsigned char* array0 = new unsigned char[4];
array0[0] = 0x00;
array0[1] = 0x11;
array0[2] = 0x22;
array0[3] = 0x33;
// the address of array1 is a multiple of 4 too:
unsigned char* array1 = new unsigned char[5];
array1[0] = 0x00;
array1[1] = 0x00;
array1[2] = 0x11;
array1[3] = 0x22; …
Run Code Online (Sandbox Code Playgroud)

c++ memory-alignment

7
推荐指数
1
解决办法
641
查看次数

是否有标准宏来检测需要对齐内存访问的架构?

假设有类似的东西:

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)

c memory-alignment c-preprocessor

7
推荐指数
1
解决办法
239
查看次数

为什么需要内存对齐?

可能重复:
内存对齐的目的

我在网上阅读了一些关于内存对齐的文章,并且可以理解,通过正确对齐的内存(采用2字节对齐),我们可以一次性快速获取数据.

但是如果我们有像一个硬件一样的内存,那么给定一个地址,为什么我们不能直接从该位置读取2字节.喜欢:在此输入图像描述

我考虑过它.我认为,如果记忆在奇偶组中,那么理论就适用了.

在此输入图像描述

我错过了什么?

c c++ memory pointers memory-alignment

7
推荐指数
2
解决办法
4130
查看次数

标准全局默认运算符new的对齐限制是什么?

我正在研究一些使用ATL CComBSTR类型的旧代码.我正在更改它,以便它将使用Visual C++ Express Edition进行编译,而Visual C++ Express Edition没有ATL.我只使用了一小部分CComBSTR,所以这样做非常简单.

但是,在分配BSTR内存块时,我需要用4字节长度的前缀填充前四个字节.我担心如果我使用new char[size]表达式为字符串分配内存,由于分配的char数组没有四字节前缀的正确对齐,我将导致对齐错误.

标准中是否有任何内容表明返回值new具有哪些对齐要求?我在C++ 11中看到的只有:

5.3.4/1 [expr.new]
是否支持过度对齐类型(3.11)是实现定义的.

3.11/6 [basic.align]
可以使用alignof表达式(5.3.6)查询完整类型的对齐要求.此外,char,signed char和unsigned char类型应具有最弱的对齐要求.[注意:这使得字符类型可以用作对齐内存区域的基础类型(7.6.2).-结束注释]

我发现这有点令人困惑 - "最弱的对齐要求"对我说"最不严格的对齐约束",但这下的注释似乎表明标准意味着相反.

我可以安全使用new char[sizeof(uint32_t) + 2*(length + 1)]缓冲区BSTR吗?

编辑:我刚才意识到,在这个特定情况下BSTR,需要使用SysAllocString来分配字符串; 但是我仍然对new以这种方式使用它是否合适感兴趣.

c++ com memory-alignment visual-c++

7
推荐指数
2
解决办法
858
查看次数

这个尺寸对齐是如何工作的

关于提供的评论,我无法理解以下代码.这段代码做了什么,以及它的等效代码是8-aligned什么?

/* segment size must be 4-aligned */
attr->options.ssize &= ~3;
Run Code Online (Sandbox Code Playgroud)

这里ssizeunsigned int类型.

c c++ struct bit-manipulation memory-alignment

7
推荐指数
3
解决办法
3153
查看次数

对.NET中未对齐字段的读写是绝对原子的吗?

C#规范(ECMA-334ISO/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上)?无论哪种方式,你有任何消息来支持这个吗?

.net c# atomic memory-alignment

7
推荐指数
1
解决办法
478
查看次数

ARMCC:memcpy问题(对齐异常)

我正在将一些软件从gcc-toolchain移植到armcc-toolchain(处理器保持不变(Cortex-A9)).在C代码中使用memcpy.armcc通过调用__aeabi_memcpy替换对memcpy的调用.常见问题解答如下关于__aeabi_memcpy(ARM编译器如何处理memcpy()?):

在许多情况下,在编译对memcpy()的调用时,ARM C编译器将生成对专用的,优化的库函数的调用.从RVCT 2.1开始,这些专用函数是ARM体系结构(AEABI)的ABI的一部分,包括:

__aeabi_memcpy
This function is the same as ANSI C memcpy, except that the return value is void.
Run Code Online (Sandbox Code Playgroud)

但是与gcc相比,在我的所有情况下对memcpy的调用都可以正常工作,使用armcc对memcpy的调用__aeabi_memcpy会连续产生对齐异常.同时我发现,对memcpy的调用可以处理源和目标地址不是4字节对齐的调用,但前提是它们都不是4字节对齐的.例如:

    volatile uint32_t len = 10;
    uint8_t* src = (uint8_t*)0x06000002;         // 2-byte aligned
    uint8_t* dst = (uint8_t*)(0x06000002 + 20);  // 2-byte aligned
    memcpy(dst, src, len);
Run Code Online (Sandbox Code Playgroud)

将工作.但是例如:

    volatile uint32_t len = 10;
    uint8_t* src = (uint8_t*)0x06000002;         // 2-byte aligned
    uint8_t* dst = (uint8_t*)(0x06000002 + 22);  // 4-byte aligned
    memcpy(dst, src, len);
Run Code Online (Sandbox Code Playgroud)

会导致对齐异常.我正在使用uint8_t类型的指针*我明确告诉编译器地址可以有任何对齐.但显然这个__aeabi_memcpy无法处理每个路线组合.如何解决此问题(最好不使用用户特定版本的memcpy更改现有代码中对memcpy的所有调用)?感谢帮助.

c memory-alignment memcpy armcc

7
推荐指数
1
解决办法
4881
查看次数

是否由于未定义的行为导致错位负载?

是否由于void*未定义的行为导致错位负载?


以下是我对Clang及其消毒剂的看法:

bufhelp.h:146:29: runtime error: load of misaligned address 0x7fff04fdd0e1 for type 'const uintptr_t' (aka 'const unsigned long'), which requires 8 byte alignment
0x7fff04fdd0e1: note: pointer points here
 00 00 00  66 66 6f 6f 62 61 72 34  32 46 4f 4f 42 41 52 31  37 66 6f 6f 62 61 72 34  33 46 4f 4f 42
              ^ 
Run Code Online (Sandbox Code Playgroud)

这是演员阵容发挥作用的地方:

buf_xor(void *_dst, const void *_src1, const void *_src2, size_t len)
{
  ...
  ldst = (uintptr_t *)(void …
Run Code Online (Sandbox Code Playgroud)

c casting memory-alignment undefined-behavior

7
推荐指数
1
解决办法
2810
查看次数

在C++中定义"分配单元"?

在讨论位域时,C++ 17标准在第12.2.4节中多次使用术语"分配单元",但似乎没有定义该术语的含义.该标准还指出,"作为特殊情况,宽度为零的未命名位域指定分配单元边界处下一个位字段的对齐."

所以我对这些概念有两个问题,使用下面的代码作为例子:

  1. 该标准的术语"分配单位"是什么意思?

  2. 为未命名的位域指定的数据类型有何意义?

在第二个问题中,我的假设是数据类型意味着后面的位字段应该在该数据类型的下一个边界上对齐.

struct tag
{
   char X:3;
   unsigned int :0;   // start next bit-field on next unsigned int boundary?
   char Y:4;
   unsigned char :0;  // start next bit-field on next unsigned char boundary?
   long Z:32;
};
Run Code Online (Sandbox Code Playgroud)

c++ memory-alignment language-lawyer bit-fields

7
推荐指数
1
解决办法
195
查看次数