对于下面的结构,结构的实际(没有填充)大小为 54。在具有 MinGW (GCC) 4.8.1 x86_64 的 64 位 (Windows 7) 计算机上,我得到的大小sizeof(BMPHeader)为 56,这是可以理解的。根据BMP文件格式的要求,该结构不应有填充。我有三个选择(优先顺序):
alignas(1)struct __attribute__ ((packed)) BMPHeader#pragma pack(1)然而,最后一个选项(优先级最低)似乎单独工作,给了我 54。这是编译器中的错误还是我在这里完全误解了一些东西?南沙商会
#include <iostream>
struct alignas(1) BMPHeader
{
// BMP header
uint16_t magic;
uint32_t fileSize;
uint32_t reserved;
uint32_t dataOffset;
// DIB header
uint32_t dibHeaderLength;
uint32_t width;
uint32_t height;
uint16_t numColourPlanes;
uint16_t bitsPerPixels;
uint32_t biBitFields;
uint32_t dataSize;
uint32_t physicalWidth;
uint32_t physicalHeight;
uint32_t numPaletteColours;
uint32_t numImportantColours;
};
int main()
{
std::cout << sizeof(BMPHeader) << std::endl;
}
Run Code Online (Sandbox Code Playgroud) 鉴于 CPU 的字长允许它寻址内存中的每个字节。
鉴于通过PAE CPU 甚至可以使用比其字长更多的位进行寻址。
CPU无法一步读取未对齐的字是什么原因?
例如,在 32 位机器中,您可以读取从位置 0 开始的 4 字节块,但不能读取从位置 1 开始的块(可以,但需要几个步骤)。
为什么CPU不能这样做?
hardware cpu-architecture memory-alignment memory-address address-bus
我目前这样做的方式(我宁愿摆脱memcpy电话):
uint64_t integer;
uint8_t string[8];
...
memcpy(&integer, &string, 8); //or swap the parameters
Run Code Online (Sandbox Code Playgroud)
假设integer数组长度始终是 8 的倍数(64 位总分配),考虑到编译器填充/对齐问题,是否可以进行直接转换?
我正在使用 Qt5 编写一个程序,我需要分配一个QVector <float>使其data()指针 32 字节对齐的指针。
无论如何,我可以在不修改 Qt 库本身的情况下做到这一点吗?
我的代码看起来像这样:
QVector <float> vec;
vec.resize(n);
float *wricker_ptr = wricker.data(); // this should be 32-byte aligned
for (int i=0; i<n; i++)
{
wricker_ptr[i] = /* some computed value */;
}
Run Code Online (Sandbox Code Playgroud)
我正在使用英特尔的 C++ 编译器。
我有一个 C 结构数组,我想填充它来读取文件(并行,使用 set_view 等)
typedef struct
{
char type;
double value;
double velocity;
} Cell;
Run Code Online (Sandbox Code Playgroud)
我的问题是,一些文件(TYPE1)将只具有type和value(与速度的情况下,必须留给O,以及其他一些文件(2型)都在我type,value和velocity
因此,在读取n文件中的块时,我要么读取 nx 9 位(case1)要么读取 nx 17 位((case2),我必须将它们以良好的对齐方式放入缓冲区。
我从一个mpi_cell_aligned类型开始
MPI_Datatype mpi_cell_aligned;
int count[] = { 1, 1, 1 };
MPI_Aint displ[] = { offsetof(Cell, type), offsetof(Cell, value), offsetof(Cell, velocity) };
MPI_Datatype types[] = { MPI_CHAR, MPI_DOUBLE, MPI_DOUBLE };
switch(type)
{
case 1: MPI_Type_create_struct(2, count, displ, types, &mpi_cell_aligned); break;
case 2: MPI_Type_create_struct(3, …Run Code Online (Sandbox Code Playgroud) 我最近研究了一个用GCC 8编译的软件中的segfault。代码如下(这只是一个草图)
struct Point
{
int64_t x, y;
};
struct Edge
{
// some other fields
// ...
Point p; // <- at offset `0xC0`
Edge(const Point &p) p(p) {}
};
Edge *create_edge(const Point &p)
{
void *raw_memory = my_custom_allocator(sizeof(Edge));
return new (raw_memory) Edge(p);
}
Run Code Online (Sandbox Code Playgroud)
这里的关键点是my_custom_allocator()返回指向未对齐内存的指针。代码崩溃是因为为了将原始点复制p到Edge::p新对象的字段中,编译器在 [内联] 构造函数代码中使用了movdqu/movaps对
movdqu 0x0(%rbp), %xmm1 ; read the original object at `rbp`
...
movaps %xmm1, 0xc0(%rbx) ; store it into the new `Edge` object …Run Code Online (Sandbox Code Playgroud) 在下面的代码中,我定义了一个9 字节的结构头,它与 16 字节的大小对齐。然后我从堆中动态分配 9 个字节并将其分配给标头指针。
struct header
{
uint8_t chunk_id;
long int format;
};
int main()
{
std::cout << "sizeof(header) " << sizeof(header) << '\n';
auto head = (header*)malloc(9);
head->chunk_id =3;
head->format=5;
std::cout << (int)head->chunk_id << " " << head->format << '\n' << sizeof(*head);
free(head);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
sizeof(header) 16
3 5
16
Run Code Online (Sandbox Code Playgroud)
事实证明,sizeof仍然通知这个对象是 16 个字节(尽管它是 9 个)。我想它只是看结构的定义。但是,当sizeof的大小与实际对象大小不匹配时,一切如何工作(包括运算符“->”)?
我刚刚了解alignof和alignasC ++的关键字,但我不敢去想如果开发者希望使用这些关键字的任何实际的案例。
有人知道这些关键字的任何实际用例吗?
我从 NASM 的文档中看到了以下规则:
在进行调用之前,堆栈指针 %rsp 必须与 16 字节边界对齐。很好,但是进行调用的过程会将返回地址(8 个字节)压入堆栈,因此当函数获得控制权时,%rsp 未对齐。你必须自己创造额外的空间,通过推动某些东西或从 %rsp 中减去 8。
我有一段 NASM 汇编代码,如下所示:
在我调用“_start”中的函数“inc”之前,%rsp 应该位于 8 字节的边界,这违反了 NASM 文档中描述的规则。但实际上,一切都在进行中。那么,我如何理解这一点呢?
我是在 Ubuntu 20.04 LTS (x86_64) 下构建的。
global _start
section .data
init:
db 0x2
section .rodata
codes:
db '0123456789abcdef'
section .text
inc:
mov rax, [rsp+8] ; read param from the stack;
add rax, 0x1
ret
print:
lea rsi, [codes + rax]
mov rax, 1
mov rdi, 1
mov rdx, 1
syscall
ret
_start:
; enable AC check;
pushf
or …Run Code Online (Sandbox Code Playgroud) 对于大多数 C 编译器,可以在结构上指定编译器属性,该属性定义该结构的成员在内存中的对齐方式。前任:
typedef struct{
char a;
char b;
} __attribute__((aligned(2))) TwoChars;
Run Code Online (Sandbox Code Playgroud)
如果char a以地址 0xA 结束(为简单起见),则char b不会在地址 0xB 处,而是在 0xC 处,因为它与 2 个字节对齐。
我的问题是:这个属性是由结构成员继承的吗?前任:
typedef struct{
char a;
char b;
} TwoChars;
typedef struct {
TwoChars tc;
char c;
} __attribute__((aligned(1))) ThreeChars;
Run Code Online (Sandbox Code Playgroud)
这在内存中最终会是什么样子?怎么样} __attribute__((aligned(2))) TwoChars?