我知道根据 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) 根据这个答案:
最小对齐(在给定平台上)是不会崩溃的对齐。
在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? …
我在某些计算带有整数操作数的浮点表达式的代码中遇到了 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例如在堆栈上分配了一个整数。
所以我的问题是:
我对《计算机系统:程序员的视角》 (第 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)
书中给出的答案:
| 我 | C | j | d | 全部的 |
|---|---|---|---|---|
| 0 | 2 | 6 | 14 | 16 |
| w | C | 全部的 |
|---|---|---|
| 0 | 16 | 32 |
| A | t | 全部的 |
|---|---|---|
| 0 | 24 | 40 |
我不明白的是为什么 did struct P4 a[2]inP5只需要 24 个字节?
既然P5.a是一个大小为2的数组P4 …
在我的自定义.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_cast对uint32_t*和相同的解引用.我知道,memcpy到uint32_t会解决这个问题,但我要这么做?我看到许多广泛使用的库(如pixman,cairo ......)都有同样的警告.
假设我正在使用一个结构在堆上分配并用作
然后我可以简单地重载它的新数组运算符,不要触摸任何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.
如果您去年一直活跃在编程社区中,那么您肯定听到过对 Rust 执行速度和性能以及ResultRust 中出色类型的赞扬。
我可能应该提一下,我不是 Rust 开发人员。尽管如此,或者甚至可能正因为如此,我想知道如果 Rust 使用这个 Result 类型,它怎么会如此高效,因为就我而言,这个类型被实现为所谓的union在C . 它在联合中包含一个错误和一个返回值,其中在给定时间只有一个有效。该类型还包含一个标志,指示结果是否包含错误或值。
如果我计数正确,并且假设错误存储为指针或引用(例如,在 64 位系统上占用内存中的 8 个字节),则联合最少 8 个字节 + 标志一个字节,使得9字节内存。
现在,通过填充,我假设在大多数系统上,这将被重新对齐以占用 12 个字节。相比之下,返回 int(32) 仅分配 4 个字节。因此,使用 Result 分配的内存应该是使用 int 的三倍。
这不是极大地浪费内存吗?我想象在循环中运行它,这会增加很多。
我不太明白为什么有人会声称 Rust 性能超级好,而 Result 却占用了那么多内存?
我知道有一些优化技巧可以减少内存使用量,例如使用带有选项的 NotZeroInt 使编译器可以使用零作为标志,从而避免为标志提供额外的字节。但对于大多数类型来说这并不适用,不是吗?
如果有人有进一步的见解,我很想听听。请注意,我不是 Rust 开发人员,出于好奇而提出这个问题,正如我在尝试移植此功能的库中观察到的那样,内存使用量急剧增加。
当然,RustResult<T, E>和Option<T>类型比某些移植库进行了更好的优化,但我无法想象这如何不会影响程序性能。
我检查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'.这是问题的关键.
我有以下内容:
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 ×4
c++ ×4
memory ×2
amazon-ec2 ×1
arm ×1
arrays ×1
assembly ×1
gcc ×1
linux ×1
performance ×1
rust ×1
sizeof ×1
struct ×1
type-punning ×1
union ×1