标签: memory-alignment

我如何知道从计算机上未对齐的内存地址读取是否安全?

我知道根据 C 标准,不允许执行未对齐的内存读取,因为它可能会导致SIGBUS.

不过,我见过一些机器,这不是问题。

我如何知道从计算机上未对齐的内存中读取数据是否安全?更具体地说,我正在使用 Amazon Linux。

$ lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                8
On-line CPU(s) list:   0-7
Thread(s) per core:    2
Core(s) per socket:    4
Socket(s):             1
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 60
Stepping:              3
CPU MHz:               800.000
BogoMIPS:              7981.41
Virtualization:        VT-x
L1d cache:             32K
L1i cache:             32K
L2 cache:              256K
L3 cache:              8192K
NUMA node0 CPU(s):     0-7
Run Code Online (Sandbox Code Playgroud)

c linux amazon-ec2 memory-alignment

0
推荐指数
1
解决办法
290
查看次数

为什么我可以将变量存储在不是其最小对齐倍数的地址处?

根据这个答案

最小对齐(在给定平台上)是不会崩溃的对齐。

GCC 8中,有两个函数可以获取最小对齐和首选对齐:

  • alignof给出最小对齐的标准运算符
  • __alignof__给出首选对齐方式的GNU函数

对于 a double,最小对齐为 4 字节,在 i386 架构上首选对齐为 8 字节。因此,如果我正确理解了上面引用的答案,即应用程序将 a 存储double在不是 4 的倍数的地址处,则程序应该崩溃。

我们看下面的代码:

#include <iostream>

void f(void* ptr) {
    double* ptr_double = (double*) ptr;
    ptr_double[0] = 3.5;
    std::cout << ptr_double[0] << std::endl;
    std::cout << &ptr_double[0] << std::endl;
}

int main()
{
    alignas(__alignof__(double)) char arr[9];
    f(arr+1);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我使用-m32选项编译它,它运行良好并且得到以下结果:

3.5
0xffe41571
Run Code Online (Sandbox Code Playgroud)

我们可以看到我的double没有对齐,但程序运行没有任何问题。

上面引用的下一句话是:

在 x86-64 上它是一个字节。

在某些方面,这似乎是正确的,因为我的代码可以工作。但是,在这种情况下,为什么alignof返回 4? …

c++ memory-alignment

0
推荐指数
1
解决办法
149
查看次数

如何避免在皮质 M4 上浮动的未对齐访问异常

我在某些计算带有整数操作数的浮点表达式的代码中遇到了 HardFault 异常。操作数按地址传递,然后将其转换(隐式或显式转换)为浮点数。当操作数不是 32 位对齐时(这不在我的控制之下),我得到异常。

我试图在这里重现 Godbolt 上的行为,生成的代码与我在设备上得到的一致。

基本上,下面的反汇编代码

vldr.32 s0, [r0]  @ int
Run Code Online (Sandbox Code Playgroud)

vldr需要对齐地址的指令中直接使用传递给函数的可能未对齐的地址。

我发现这个问题解决了类似的问题,但他们在那里谈论浮点指针。在这种情况下,我知道浮动不能未对齐。

在我的情况下,我正在处理整数,允许未对齐,但编译器假定它仍然可以使用 vldr 指令中的地址。更让我困惑的是这段代码

uint32_t pippo =  *(uint32_t *)src;

float pippof = pippo * 10.0f;
Run Code Online (Sandbox Code Playgroud)

当提供未对齐的地址时,可能会或可能不会产生异常,这取决于优化级别,因为-O0例如在堆栈上分配了一个整数。

所以我的问题是:

  • 这是编译器(或后端,也许)的正确行为吗?由于整数可以未对齐,我希望生成的代码从 CPU 寄存器传递。
  • 当即使通过临时 int 变量也不安全时,避免此类问题的正确策略是什么?

c assembly gcc arm memory-alignment

0
推荐指数
1
解决办法
317
查看次数

结构体数组占用的空间

我对《计算机系统:程序员的视角》 (第 3 版(2015 年 10 月 6 日))一书的问题 3.44 有关数据对齐的问题有疑问。

问题:

对于以下每个结构声明,确定每个字段的偏移量,即结构的总大小,以进行 8 位对齐:

struct P1 {short i; int c; int *j; short *d}
...
struct P4 {char w[16]; char *c[2]}
struct P5 {struct P4 a[2]; struct P1 t}
Run Code Online (Sandbox Code Playgroud)

书中给出的答案:

  • 结构P1:
C j d 全部的
0 2 6 14 16
  • 结构P4:
w C 全部的
0 16 32
  • 结构P5:
A t 全部的
0 24 40

我不明白的是为什么 did struct P4 a[2]inP5只需要 24 个字节?
既然P5.a是一个大小为2的数组P4 …

c memory-alignment

0
推荐指数
1
解决办法
84
查看次数

不对齐警告修复它们或不修复它们?

在我的自定义.zip解压缩器中,我得到这样的警告:

runtime error: load of misaligned address 0x7f280ffe875a for type 'const uint32_t', which requires 4 byte alignment
Run Code Online (Sandbox Code Playgroud)

究其原因是reinterpret_castuint32_t*和相同的解引用.我知道,memcpyuint32_t会解决这个问题,但我要这么做?我看到许多广泛使用的库(如pixman,cairo ......)都有同样的警告.

c++ memory-alignment type-punning

-1
推荐指数
1
解决办法
289
查看次数

重载新阵列运算符的安全性如何?

假设我正在使用一个结构在堆上分配并用作

  • new []和delete []
  • shared_ptr(new [])

然后我可以简单地重载它的新数组运算符,不要触摸任何delete []运算符

struct  alignas(256)  MyStruct
{
    Item i1,i2;
    void * operator new[](unsigned long int size)
    {
        return aligned_alloc(256,size);
    }

    void * operator new (unsigned long int size)
    {
        return aligned_alloc(256,size);
    }
};
Run Code Online (Sandbox Code Playgroud)

并认为它没有任何泄漏?

GCC 6.3和c ++ 0x.

c++ operator-overloading memory-alignment

-1
推荐指数
1
解决办法
388
查看次数

Rust 中的 Result&lt;T, E&gt; 怎么这么快?

如果您去年一直活跃在编程社区中,那么您肯定听到过对 Rust 执行速度和性能以及ResultRust 中出色类型的赞扬。

我可能应该提一下,我不是 Rust 开发人员。尽管如此,或者甚至可能正因为如此,我想知道如果 Rust 使用这个 Result 类型,它怎么会如此高效,因为就我而言,这个类型被实现为所谓的unionC . 它在联合中包含一个错误和一个返回值,其中在给定时间只有一个有效。该类型还包含一个标志,指示结果是否包含错误或值。

如果我计数正确,并且假设错误存储为指针或引用(例如,在 64 位系统上占用内存中的 8 个字节),则联合最少 8 个字节 + 标志一个字节,使得9字节内存。

现在,通过填充,我假设在大多数系统上,这将被重新对齐以占用 12 个字节。相比之下,返回 int(32) 仅分配 4 个字节。因此,使用 Result 分配的内存应该是使用 int 的三倍。

这不是极大地浪费内存吗?我想象在循环中运行它,这会增加很多。

我不太明白为什么有人会声称 Rust 性能超级好,而 Result 却占用了那么多内存?

我知道有一些优化技巧可以减少内存使用量,例如使用带有选项的 NotZeroInt 使编译器可以使用零作为标志,从而避免为标志提供额外的字节。但对于大多数类型来说这并不适用,不是吗?

如果有人有进一步的见解,我很想听听。请注意,我不是 Rust 开发人员,出于好奇而提出这个问题,正如我在尝试移植此功能的库中观察到的那样,内存使用量急剧增加。

当然,RustResult<T, E>Option<T>类型比某些移植库进行了更好的优化,但我无法想象这如何不会影响程序性能。

memory performance union memory-alignment rust

-1
推荐指数
1
解决办法
156
查看次数

为什么C数组尾部有额外的字节?

我检查C数组可能在尾部有一些额外的字节.

有我的代码

int a = 5;
int test[] = {1,2,3,4};
int b = 5;

test[-1] = 11;
test[4] = 11;

cout << b << endl; // 11 
cout << a << endl; // 5
Run Code Online (Sandbox Code Playgroud)

你可以在那里看到运行结果

的值b是通过改变改变test[-1]的值.但是,当我改变test[4]价值时,价值a不会改变;

我用gdb检查他们的地址,发现了

在g ++ 6.4.0中,a减法地址的地址test[4]是8字节
在clang ++ 3.8.1中,a减法地址的地址test[4]是4字节

所以,我很好奇为什么数组在尾部有一些字节?

感谢@Peter A.Schneider解释这个问题.它肯定是UB,但它只是一个实验性代码.这不是实际代码的讨论.

通常,运行时堆栈中的变量靠得很近.b接近测试,但为什么'a'不接近'test + 3'.这是问题的关键.

c++ arrays memory-alignment

-2
推荐指数
1
解决办法
68
查看次数

结构组件不相加

我有以下内容:

typedef struct
{
    string city;
    int temp;
}
avg_temp;

avg_temp temps[NUM_CITIES];

void sort_cities(void);

int main(void)
{
    temps[0].city = "Austin";
    temps[0].temp = 97;

    temps[1].city = "Boston";
    temps[1].temp = 82;

    temps[2].city = "Chicago";
    temps[2].temp = 85;

    temps[3].city = "Denver";
    temps[3].temp = 90;

    temps[4].city = "Las Vegas";
    temps[4].temp = 105;

    temps[5].city = "Los Angeles";
    temps[5].temp = 82;

    temps[6].city = "Miami";
    temps[6].temp = 97;

    temps[7].city = "New York";
    temps[7].temp = 85;

    temps[8].city = "Phoenix";
    temps[8].temp = 107;

    temps[9].city = "San Francisco";
    temps[9].temp = …
Run Code Online (Sandbox Code Playgroud)

c memory struct sizeof memory-alignment

-2
推荐指数
1
解决办法
70
查看次数