malloc 和 C 对齐:这种手工优化安全吗?

发布于 2025-01-13 14:22:20 字数 1019 浏览 4 评论 0原文

我放置了整个代码,但是当然,它位于不同的文件中(.h.c 文件)

typedef unsigned char ubyte;
typedef unsigned int uint;
#include<stdbool.h>

typedef struct Cube {
    ubyte n;
    ubyte e;
    ubyte s;
    ubyte w;
} Cube;

typedef struct Piece {
    Cube c;
    bool is_main;
    char offset_n;
    char offset_s;
} Piece;

typedef struct Block {
    ubyte total;
    Piece* pieces;
} Block;

Block *block_create(uint nb_pieces) {
    Block *block = malloc(sizeof(Block) + (sizeof(Piece) * nb_pieces));
    block->pieces = (Piece *) (&block + sizeof(Block));
    return block;
}

我只是想知道这行代码是否:block ->pieces = (&block + sizeof(Block));始终安全。我的意思是:我们能否确定,在 sizeof(Piece) 之后,我们将立即得到 (sizeof(Piece) * nb_pieces) ?我们确定永远不会出现对齐问题吗(即,如果是 64 位对齐,sizeof(Block) 的内存将小于 8 个字节,并且 block->pieces 不应该精确指向 sizeof(Block),而是“sizeof(Block) 64 位对齐”。

我希望我说得足够清楚。

I put the whole code but, of course, it's in different files (.h and .c files)

typedef unsigned char ubyte;
typedef unsigned int uint;
#include<stdbool.h>

typedef struct Cube {
    ubyte n;
    ubyte e;
    ubyte s;
    ubyte w;
} Cube;

typedef struct Piece {
    Cube c;
    bool is_main;
    char offset_n;
    char offset_s;
} Piece;

typedef struct Block {
    ubyte total;
    Piece* pieces;
} Block;

Block *block_create(uint nb_pieces) {
    Block *block = malloc(sizeof(Block) + (sizeof(Piece) * nb_pieces));
    block->pieces = (Piece *) (&block + sizeof(Block));
    return block;
}

I am just wondering if this line of code: block->pieces = (&block + sizeof(Block)); will be always safe. I mean: can we be sure that, immediately after the sizeof(Piece), we will have precisely (sizeof(Piece) * nb_pieces)? Are we sure there will never be an alignment problem (ie maybe if it's 64-bits aligned, the memory for sizeof(Block) will be less than 8 bytes and the block->pieces should not point to exactly sizeof(Block), but "sizeof(Block) 64 bits-aligned").

I hope I'm clear enough.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

旧梦荧光笔 2025-01-20 14:22:20

首先,这并没有达到您的预期,并且有多种原因:

block->pieces = (&block + sizeof(Block));

首先, &block 是变量 block 的地址,而不是 的内容块,并且类型为block **。最多,您可以安全地为该指针值添加 1,因为更多的值将创建一个超出该变量末尾的指针,而该指针是无效的。

因此,您需要将 &block 更改为 block。这仍然不会达到您的预期,因为指针算术会将原始地址增加对象大小的倍数。因此,添加 sizeof(Block) 并不是向上移动 1 个数组元素,而是向上移动 sizeof(Block) 数组元素。

要解决此问题,您需要 block + 1。现在您需要开始担心对齐问题。为了使 Pieces 数组正确对齐,您需要检查 _Alignof(Block)_Alignof(Piece) 是否相同。如果没有,您将需要添加填充字节:

int padding = 0;
if (_Alignof(Block) % _Alignof(Piece) != 0) {
    padding = _Alignof(Piece) - (_Alignof(Block) % _Alignof(Piece));
}
Block *block = malloc(sizeof(Block) + padding + (sizeof(Piece) * nb_pieces));
block->pieces = (Piece *)((char *)(block + 1) + padding);

当然,您可以通过使 pieces 成员成为灵活数组成员来避免这一切:

typedef struct Block {
    ubyte total;
    Piece pieces[];
} Block;

并且分配本身将是足够的。

First, this isn't doing what you expect, and for multiple reasons:

block->pieces = (&block + sizeof(Block));

First, &block is the address of the variable block, not the contents of block, and has type block **. At most, you can safely add 1 this pointer value because anything more will create a pointer past the end of this variable which is invalid.

So then you would need to change &block to block. That still won't do what you expect because pointer arithmetic increments the raw address by multiples of the object size. So adding sizeof(Block) to this is not moving up 1 array element but moving up sizeof(Block) array elements.

To fix this you would need block + 1. Now you need to start worrying about alignment. For your array of Pieces to be aligned properly, you would need to check if _Alignof(Block) and _Alignof(Piece) are the same. If not, you would need to add padding bytes:

int padding = 0;
if (_Alignof(Block) % _Alignof(Piece) != 0) {
    padding = _Alignof(Piece) - (_Alignof(Block) % _Alignof(Piece));
}
Block *block = malloc(sizeof(Block) + padding + (sizeof(Piece) * nb_pieces));
block->pieces = (Piece *)((char *)(block + 1) + padding);

Of course, you can avoid all this by making the pieces member a flexible array member:

typedef struct Block {
    ubyte total;
    Piece pieces[];
} Block;

And the allocation by itself will be enough.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文