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.
CodePudding user response:
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.