malloc + size_t * 3 的地址是否为任何类型对齐?
Is the address of malloc + size_t * 3 aligned for any type?
我正在构建一种动态数组(向量),但不是将数据(通常是 void *
)嵌入到 struct vector
中,而是保留 space a struct vector
+ 一大块字节,一个使用 size_t
数组的例子:
#include <stdio.h>
#include <stdlib.h>
struct vector {
size_t capacity;
size_t typesize;
size_t size;
};
#define VECTOR(v) ((struct vector *)((unsigned char *)v - sizeof(struct vector)))
static void *valloc(size_t typesize, size_t size)
{
struct vector *vector;
unsigned char *data;
data = calloc(1, sizeof(*vector) + typesize * size);
if (data == NULL) {
return NULL;
}
vector = (struct vector *)data;
vector->typesize = typesize;
vector->capacity = size;
vector->size = 0;
return data + sizeof(*vector);
}
static void *vadd(void *data)
{
struct vector *vector = VECTOR(data);
unsigned char *new;
size_t capacity;
if (vector->size >= vector->capacity) {
capacity = vector->capacity * 2;
new = realloc(vector, sizeof(*vector) + vector->typesize * capacity);
if (new == NULL) {
return NULL;
}
vector = (struct vector *)new;
vector->capacity = capacity;
vector->size++;
return new + sizeof(*vector);
}
vector->size++;
return data;
}
static size_t vsize(void *data)
{
return VECTOR(data)->size;
}
static void vfree(void *data, void (*func)(void *))
{
struct vector *vector = VECTOR(data);
if (func != NULL) {
for (size_t iter = 0; iter < vector->size; iter++) {
func(*(void **)((unsigned char *)data + iter * vector->typesize));
}
}
free(vector);
}
int main(void)
{
size_t *data;
data = valloc(sizeof(size_t), 1);
if (data == NULL) {
perror("valloc");
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < 10; i++) {
data = vadd(data);
if (data == NULL) {
perror("vadd");
exit(EXIT_FAILURE);
}
data[i] = i;
}
for (size_t i = 0; i < vsize(data); i++) {
printf("%zu\n", data[i]);
}
vfree(data, NULL);
return 0;
}
问题是:malloc
(void *
) 的结果地址 + struct
的大小是否对任何类型都对齐?此代码的行为是否定义明确?
Is the address of malloc + size_t * 3 aligned for any type?
不,不一定。
确定基本对齐 通过使前缀数据也成为基本对齐。
一种方法是使用 struct vector
和 max_align_t
中的 union
。 union uvector
的大小将是 基本对齐方式 的倍数。
max_align_t
which is an object type whose alignment is as great as is supported by the implementation
in all contexts;
union uvector {
max_align_t a;
struct vector {
size_t capacity;
size_t typesize;
size_t size;
} v;
};
union uvector *uvector;
unsigned char *data;
data = calloc(1, sizeof *uvector ...
...
return data + sizeof *uvector;
答案有一些低效 - 在另一个答案中修改了..
Is the address of malloc + size_t * 3 aligned for any type?
不,因为标准类型可能比 size_t
具有更高的对齐要求。标准类型的对齐要求将是编译器使用的许多基本对齐之一。
C11 的 <stddef.h>
定义了一个标准类型 max_align_t
,其对齐方式与实现支持的任何标准类型一样好。 (可能有比 max_align_t
更高对齐要求的扩展类型。)C11 也有 _Alignof
和 _Alignas
关键字。
_Alignof
是一个对类型进行运算的运算符,其结果是一个整数常量表达式,等于该类型的对齐要求(以字节为单位)。最大的基本对齐由_Alignof(max_align_t)
给出。
_Alignas
关键字在 对齐说明符 中用作声明的一部分,以增加声明的对象或成员的对齐要求。 (它不能用于降低对象或成员的对齐要求。)对齐说明符具有以下形式之一:
_Alignas
(
类型名称 )
_Alignas
(
常量表达式 )
其中 constant-expression 以字节为单位指定所需的对齐方式。第一种形式 type-name 等同于 _Alignas
(
_Alignof
(
类型名称 )
)
.
您可以使用对齐说明符将 struct vector
的第一个成员的对齐要求增加到最大基本对齐,如下所示:
struct vector {
_Alignas(max_align_t)
size_t capacity;
size_t typesize;
size_t size;
};
由于 struct vector
的第一个成员现在具有最大可能的基本对齐方式,因此 struct vector
作为一个整体具有相同的对齐要求(除非它包含需要 扩展对齐)。如有必要。编译器在 struct vector
的末尾添加额外的填充以确保 sizeof(struct vector)
是 _Alignof(max_align_t)
.
的倍数
我正在构建一种动态数组(向量),但不是将数据(通常是 void *
)嵌入到 struct vector
中,而是保留 space a struct vector
+ 一大块字节,一个使用 size_t
数组的例子:
#include <stdio.h>
#include <stdlib.h>
struct vector {
size_t capacity;
size_t typesize;
size_t size;
};
#define VECTOR(v) ((struct vector *)((unsigned char *)v - sizeof(struct vector)))
static void *valloc(size_t typesize, size_t size)
{
struct vector *vector;
unsigned char *data;
data = calloc(1, sizeof(*vector) + typesize * size);
if (data == NULL) {
return NULL;
}
vector = (struct vector *)data;
vector->typesize = typesize;
vector->capacity = size;
vector->size = 0;
return data + sizeof(*vector);
}
static void *vadd(void *data)
{
struct vector *vector = VECTOR(data);
unsigned char *new;
size_t capacity;
if (vector->size >= vector->capacity) {
capacity = vector->capacity * 2;
new = realloc(vector, sizeof(*vector) + vector->typesize * capacity);
if (new == NULL) {
return NULL;
}
vector = (struct vector *)new;
vector->capacity = capacity;
vector->size++;
return new + sizeof(*vector);
}
vector->size++;
return data;
}
static size_t vsize(void *data)
{
return VECTOR(data)->size;
}
static void vfree(void *data, void (*func)(void *))
{
struct vector *vector = VECTOR(data);
if (func != NULL) {
for (size_t iter = 0; iter < vector->size; iter++) {
func(*(void **)((unsigned char *)data + iter * vector->typesize));
}
}
free(vector);
}
int main(void)
{
size_t *data;
data = valloc(sizeof(size_t), 1);
if (data == NULL) {
perror("valloc");
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < 10; i++) {
data = vadd(data);
if (data == NULL) {
perror("vadd");
exit(EXIT_FAILURE);
}
data[i] = i;
}
for (size_t i = 0; i < vsize(data); i++) {
printf("%zu\n", data[i]);
}
vfree(data, NULL);
return 0;
}
问题是:malloc
(void *
) 的结果地址 + struct
的大小是否对任何类型都对齐?此代码的行为是否定义明确?
Is the address of malloc + size_t * 3 aligned for any type?
不,不一定。
确定基本对齐 通过使前缀数据也成为基本对齐。
一种方法是使用 struct vector
和 max_align_t
中的 union
。 union uvector
的大小将是 基本对齐方式 的倍数。
max_align_t
which is an object type whose alignment is as great as is supported by the implementation in all contexts;
union uvector {
max_align_t a;
struct vector {
size_t capacity;
size_t typesize;
size_t size;
} v;
};
union uvector *uvector;
unsigned char *data;
data = calloc(1, sizeof *uvector ...
...
return data + sizeof *uvector;
答案有一些低效 - 在另一个答案中修改了..
Is the address of malloc + size_t * 3 aligned for any type?
不,因为标准类型可能比 size_t
具有更高的对齐要求。标准类型的对齐要求将是编译器使用的许多基本对齐之一。
C11 的 <stddef.h>
定义了一个标准类型 max_align_t
,其对齐方式与实现支持的任何标准类型一样好。 (可能有比 max_align_t
更高对齐要求的扩展类型。)C11 也有 _Alignof
和 _Alignas
关键字。
_Alignof
是一个对类型进行运算的运算符,其结果是一个整数常量表达式,等于该类型的对齐要求(以字节为单位)。最大的基本对齐由_Alignof(max_align_t)
给出。
_Alignas
关键字在 对齐说明符 中用作声明的一部分,以增加声明的对象或成员的对齐要求。 (它不能用于降低对象或成员的对齐要求。)对齐说明符具有以下形式之一:
_Alignas
(
类型名称)
_Alignas
(
常量表达式)
其中 constant-expression 以字节为单位指定所需的对齐方式。第一种形式 type-name 等同于 _Alignas
(
_Alignof
(
类型名称 )
)
.
您可以使用对齐说明符将 struct vector
的第一个成员的对齐要求增加到最大基本对齐,如下所示:
struct vector {
_Alignas(max_align_t)
size_t capacity;
size_t typesize;
size_t size;
};
由于 struct vector
的第一个成员现在具有最大可能的基本对齐方式,因此 struct vector
作为一个整体具有相同的对齐要求(除非它包含需要 扩展对齐)。如有必要。编译器在 struct vector
的末尾添加额外的填充以确保 sizeof(struct vector)
是 _Alignof(max_align_t)
.