提问人:P.Jo 提问时间:10/17/2023 更新时间:10/17/2023 访问量:93
Malloc 和对齐方式
Malloc and alignment
问:
据我所知,每种类型(如 int)都只能存储在以 2 的幂开头的内存地址中。现在我的问题是,malloc 如何应对这一要求?例如,如果我调用
void * ptr;
ptr = malloc(8);
那么我想在给定的 8 字节内存块中存储什么就不明显了。因此,malloc 总是返回块的起始地址,该地址位于 2 的最大幂,以便可以存储每个标准类型,这是真的吗?如果我误解了什么,请随时纠正我。
答:
4赞
Eric Postpischil
10/17/2023
#1
C 2018 7.22.3 指定了内存分配例程的行为,其第 1 段说“......如果分配成功,则返回的指针已适当对齐,以便可以将其分配给指向具有基本对齐要求的任何类型的对象的指针......”
6.2.8 2说道:
...以下类型的对齐要求应为基本对齐:
所有原子、合格或不合格的基本类型;
所有原子、合格或非合格枚举类型;
所有原子、合格或不合格的指针类型;
元素类型具有基本对齐要求的所有数组类型;
第 7 条中指定为完整对象类型的所有类型;
所有结构或联合类型:其所有元素都具有具有基本对齐要求的类型,并且其元素均未具有指定非基本对齐方式的对齐说明符。
6.2.5 14说:
类型、有符号和无符号整数类型以及浮点类型统称为基本类型。
char
评论
0赞
Lundin
10/17/2023
这句话的其余部分似乎也很相关:“......然后用于在分配的空间中访问这样的对象或此类对象的数组“,特别是数组部分。
0赞
Eric Postpischil
10/17/2023
@Lundin:这部分与对齐无关。问题是关于对齐的。
0赞
Lundin
10/17/2023
“访问对象数组”究竟如何与对齐无关?
0赞
Eric Postpischil
10/17/2023
@Lundin:“访问对象数组”没有说明内存的对齐方式。它说读取或写入对象的语义是定义的,而不是对象所在的位置。数组的元素按照其类型的要求对齐,这在数学上遵循以下事实:起始地址按要求对齐,并且任何数组元素的大小必须是其对齐要求的多个部分(来自标准的其他部分)。
0赞
Lundin
10/17/2023
对齐方式小于“基本”的类型(如 a)被分配为连续数组而不是 2 个字节 + 填充,可能并不明显。否则,在处理结构对象数组时可能会出现这种情况。uint16_t
2赞
Nierusek
10/17/2023
#2
从:man
malloc() 和 calloc() 函数返回指向已分配内存的指针,该指针与 任何内置类型。
所以它将是对齐的。我还想补充一点,你错了:
据我所知,每种类型(如 int)都只能存储在以 2 的幂开头的内存地址中。
下面的代码在 x86_64 上运行良好,但在 ARM 上运行不正常。
#include <stdio.h>
int main() {
int a[3];
a[0] = a[1] = a[2] = 0;
int *b = 1 + (void *)&a[1];
*b = 6;
printf("%x %x %x", a[0], a[1], a[2]);
}
如您所见,指针未对齐为 4 个字节,但它将起作用。
评论
3赞
Jonathan Leffler
10/17/2023
请注意,C 标准规定您不能对指向 的指针进行算术运算。这条线是严格允许的。GCC 确实允许对值进行算术运算,将它们视为等价于 .void
int *b = 1 + (void *)&a[1];
void*
char *
1赞
chux - Reinstate Monica
10/17/2023
@Nierusek,在我的x86_64计算机上,我收到编译器警告“警告:在算术 [-Wpointer-arith] 中使用了类型为'void *'的指针”。您使用的是哪个编译器和警告级别?
0赞
Nierusek
10/17/2023
@chux-ReinstateMonica 我用过旗帜和.在我添加后,它确实向我显示了一个警告。我忘了算术是 GCC 扩展。gcc (Debian 10.2.1-6) 10.2.1
-Wall
-Wextra
-Wpointer-arith
void *
评论