#include <stddef.h>
#include <stdlib.h>
/*** Constants */
enum e_rgb {
Red,
Green,
Blue,
RGBCount
};
/*** Object types */
typedef unsigned char rgb[RGBCount];
/*** Function declarations */
struct s_picture * alloc_picture(int w, int h);
rgb * picture_row(struct s_picture * pic, int row);
/*** Struct/union definitions */
struct s_picture {
int width;
int height;
rgb * data;
};
/*** Function definitions */
int main(void) {
struct s_picture * pic;
rgb * row_ten;
/* Allocate a 10 x 10 picture */
pic = alloc_picture(10, 10);
if (!pic)
return EXIT_FAILURE;
/* Produce a pointer to the tenth row */
row_ten = picture_row(pic, 9);
/* The next three sections all do the same thing */
Red[*row_ten] = 42;
Green[*row_ten] = 42;
Blue[*row_ten] = 42;
row_ten[0][Red] = 42;
row_ten[0][Green] = 42;
row_ten[0][Blue] = 42;
(*row_ten)[Red] = 42;
(*row_ten)[Green] = 42;
(*row_ten)[Blue] = 42;
/* Clean-up and terminate */
return EXIT_SUCCESS;
}
/* Allocate storage for a picture */
struct s_picture * alloc_picture(int w, int h) {
/* Wrap up a picture */
struct s_wrapper {
struct s_picture pic[1];
/* This member is here for alignment */
rgb data[1];
};
size_t size;
void * ptr;
struct s_wrapper * wrapper;
unsigned char * bytes;
/* Compute the amount of storage to allocate */
size = (
/* Don't allocate for the alignment member */
+ sizeof wrapper->data * w * h
);
if (size < sizeof *wrapper)
size = sizeof *wrapper;
/* Allocate the storage */
/* Return a null pointer on failure */
if (!ptr)
return ptr;
wrapper = ptr;
bytes = ptr;
wrapper->pic->width = w;
wrapper->pic->height = h;
/* There is a problem with the next line */
wrapper->pic->data = wrapper->data;
/*
* Since there is only one element for 'wrapper->data',
* that means that the pointer value yielded by that
* expression could have such bounds associated with it.
* Instead, we derive a pointer value from 'bytes', whose
* bounds would be those of the call to 'malloc', above
*/
wrapper
->pic
->data
= (rgb
*) (bytes
+ offsetof(struct s_wrapper
, data
)); /* That was safer */
return wrapper->pic;
}
/* Produce a pointer to the specified row in a picture */
rgb * picture_row(struct s_picture * pic, int row) {
return pic->data + row * pic->width;
}