Consider a library where you have some code. For example let's do some point X and Y manipulation.
And then you build your library where you don't want to allow users to access to your struct variable, so far I'm using this approach and it seems to work ok.
lib.h:
#ifndef __LIB_H
#define __LIB_H
#ifdef __LIB_INTERNAL
//Structure for single point
typedef struct {
int x, y;
} Point;
//Casted pointer
#define _P(in) ((Point *)(in))
#endif
//Define pointer for public use as void pointer
typedef void* Point_p;
//Create point
Point_p createPoint(int x, int y);
#endif
lib.c:
//Define LIB_INTERNAL to allow visible access
#define __LIB_INTERNAL
#include "lib.h"
#include "stdlib.h"
Point_p createPoint(int x, int y) {
Point_p p = malloc(sizeof(Point));
_P(p)->x = x; //_P is visible in this function
_P(p)->y = y;
return p;
}
main.c:
#include "lib.h"
int main() {
Point_p p = createPoint(1, 2); //OK
Point *ptr = createPoint(1, 2); //Error as Point is not visible public
p->x = 4; //Error as Point_p is void *
}
This way I'm making sure that user don't have direct access to Point variable and it is forced to use functions to perform operations on this point.
Now I'm thinking of another approach. But first, sizeof(void *) and sizeof(Point *) is always the same so I would like to use this approach by showing Point_p to lib.c as typedef Point* Point_p and to all other files which are not part of library as typedef void* Point_p.
lib.h
#ifndef __LIB_H
#define __LIB_H
#ifdef __LIB_INTERNAL
//Structure for single point
typedef struct {
int x, y;
} Point;
//Define pointer for private use as Point pointer
typedef Point* Point_p;
#else
//Define pointer for public use as void pointer
typedef void* Point_p;
#endif
//Create point
Point_p createPoint(int x, int y);
#endif
lib.c:
//Define LIB_INTERNAL to allow visible access
#define __LIB_INTERNAL
#include "lib.h"
#include "stdlib.h"
Point_p createPoint(int x, int y) {
Point_p p = malloc(sizeof(Point));
p->x = x; //_P is not needed because Point_p is visible as Point *
p->y = y;
return p;
}
main.c: the same as previous
Question
Is this undefined behavior? Because in second approach, lib.c sees Point_p as Point *, but main.c still sees it as void * and therefore lib.c has access to members directly without casting before and main.c does not have it neither can cast because Point structure is hidden.