首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >malloc + size_t *3的地址是否与任何类型对齐?

malloc + size_t *3的地址是否与任何类型对齐?
EN

Stack Overflow用户
提问于 2019-04-26 20:08:13
回答 2查看 159关注 0票数 3

我构建了一种动态数组(向量),但并没有将数据(通常是void *)嵌入到struct vector中,而是为一个struct vector +一个字节块保留了空间,这是一个使用size_t数组的示例:

代码语言:javascript
复制
#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的大小对于任何类型都是对齐的吗?这段代码的行为定义得好吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-04-26 20:16:16

对于任何类型,

+ size_t *3的地址是否对齐?

不,不一定。

通过使前缀数据也具有基本对齐来确保基本对齐。

一种方法是使用struct vectorunionmax_align_tunion uvector的大小将是基本对齐的倍数。

max_align_t,这是一种对象类型,其对齐与实现在所有上下文中所支持的一样大;

代码语言:javascript
复制
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;

答案有一些低效-在另一个答案中重写了..

票数 7
EN

Stack Overflow用户

发布于 2019-04-29 20:04:01

对于任何类型,

+ size_t *3的地址是否对齐?

不是,因为可能有一些标准类型比size_t有更高的对齐要求。标准类型的对齐要求将是编译器使用的许多基本对齐之一。

C11的<stddef.h>定义了一个标准类型max_align_t,其对齐方式与实现所支持的任何标准类型一样好。(可能有一些扩展类型具有比max_align_t更高的对齐要求。)C11还具有_Alignof_Alignas关键字。

_Alignof是对类型进行操作的运算符,其结果是一个整数常量表达式,该表达式等于该类型的对齐要求(以字节为单位)。_Alignof(max_align_t)给出了最大的基本比对。

_Alignas关键字在对齐说明符中用作声明的一部分,以增加声明的对象或成员的对齐要求。(它不能用于降低对象或成员的对齐要求。)对齐说明符具有以下形式之一:

表达式类型名称

  • _Alignas ( constant-expression )

其中常量-表达式以字节为单位指定所需的对齐方式。第一个表单的类型名相当于_Alignas (_Alignof (的类型名) )

可以使用对齐说明符将struct vector的第一个成员的对齐要求增加到最大基本对齐,如下所示:

代码语言:javascript
复制
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)的倍数。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55867320

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档