[ACCEPTED]-How to make struct members private?-struct
In your (public) header file:
typedef struct point point;
In your .c
file:
struct point
{
void *data;
};
Note 5 that users of your code will no longer be 4 able to create a point
on the stack, as the compiler 3 doesn't know how big it is. You may have 2 to provide a point_create()
function which allocates memory 1 and returns its address to the caller.
Use C++
Since jokes seem not be allowed here is the pure C version. As another commenter pointed out if you really want to protect your internals from users of your Api you have seen and used plenty of such Apis. This Apis are e.g. the Windows or Linux user mode Apis. There you create kernel objects to which you never shall have access to. The Apis to deal with kernel objects use a synthetic construct called handle which is not simply a pointer to your own object but instead it is an index to an array where the kernel has stored the relevant meta data for your object. You can use the same idea for your Apis as well. Here for example is a C-Style public Api:
// Public.h
#include <stdlib.h>
typedef enum
{
None = 0,
PointType = 1
} Types;
typedef int Handle;
Handle CreateType(Types type);
int DeleteType(Handle object);
void IncrementX(Handle point);
void PrintPoint(Handle point);
As you can see you have generic methods 15 which create and delete your objects which 14 are defined here in an enum. Your methods 13 which use the object will then need to lookup 12 the integer handle to get the meta data 11 object where the real data is stored. This 10 design is not very efficient if the objects 9 you manage are small since for every object 8 a second object is need which stores the 7 object type, handle value and the pointer 6 to the real data. But you get much stronger 5 safety guarantees such as
- Type safety
- Invalid handles are easy to find
- Double free is impossible since you can manage the free state in the meta object
A typical usage 4 of your Api might look like this:
Handle h = CreateType(PointType);
IncrementX(h);
IncrementX(h);
PrintPoint(h);
DeleteType(h);
And there 3 is the super secret implementation in private.cpp 2 where the Handle lookup array and some helper 1 methods exist:
// Private.C
#include "stdafx.h"
#include <stdlib.h>
#include <Windows.h> // for ZeroMemory
#include "Public.h"
typedef struct
{
LPVOID pData;
Types type;
Handle handle;
} HandleInfo;
typedef struct
{
int x;
int y;
} Point;
HandleInfo *pAllocated;
int HandleBuffer = 0xffff;
unsigned char bInit = 0;
HandleInfo *GetFreeHandle()
{
int i;
if( !bInit )
{
pAllocated = (HandleInfo *) malloc(sizeof(HandleInfo)*HandleBuffer);
bInit = 1;
ZeroMemory(pAllocated, sizeof(HandleInfo)*HandleBuffer);
}
for(i=0; i<HandleBuffer; i++)
{
HandleInfo *pInfo = (pAllocated+i);
if( 0 == pInfo->handle )
{
pInfo->handle = i+1;
return pInfo;
}
}
return NULL;
}
HandleInfo * GetHandleInfo(Handle h)
{
if( h <= 0 || h >= HandleBuffer-1)
{
return NULL;
}
return (pAllocated+h-1);
}
Handle CreateType(Types typeId)
{
HandleInfo *pInfo;
pInfo = GetFreeHandle();
if( NULL == pInfo )
{
return -1;
}
pInfo->type = typeId;
switch(typeId)
{
case PointType:
pInfo->pData = malloc(sizeof(Point));
ZeroMemory(pInfo->pData, sizeof(Point));
break;
}
return pInfo->handle;
}
int DeleteType(Handle object)
{
HandleInfo *pInfo = GetHandleInfo(object);
if( NULL == pInfo )
{
return -1;
}
if( pInfo->handle != 0 )
{
free(pInfo->pData);
pInfo->pData = NULL;
pInfo->handle = 0;
return 1;
}
else
{
return 0; // Handle was already closed
}
}
void *GetObjectOfCorrectType(Handle object, Types type)
{
HandleInfo *p = GetHandleInfo(object);
if( p == NULL )
{
return NULL;
}
if( p->type != type)
{
return NULL; // handle has wrong object type
}
return p->pData;
}
void IncrementX(Handle point)
{
Point *pPoint = (Point *) GetObjectOfCorrectType(point, PointType);
if( pPoint == NULL )
{
return;
}
pPoint->x++;
}
void PrintPoint(Handle point)
{
Point *pPoint = (Point *) GetObjectOfCorrectType(point, PointType);
if( pPoint == NULL )
{
return;
}
printf("Point has x: %d y: %d", pPoint->x, pPoint->y);
}
Yours, Alois Kraus
This is the pointer to implementation or pimpl idiom. See http://en.wikibooks.org/wiki/C++_Programming/Idioms#Pointer_To_Implementation_.28pImpl.29 for a tutorial 2 for C++, but the idea should work in C as 1 well.
typedef struct {
/* private members; don't access directly */
void *data;
} point;
0
You can have separate public header and 2 private header files. Some libraries have 1 conventions for this:
- Xt (X11) ->
header.h
andheaderP.h
, e.g:X11/Vendor.h
vsX11/VendorP.h
- Qt ->
header.h
vsprivate/header_p.h
, e.g:qapplication.h
vsprivate/qapplication_p.h
If you do not want to use the declaration 11 method (because you want the library user 10 to access other members of your struct, for 9 example) it is convention to prepend private 8 member with an underscore, like this:
typedef struct {
void * _data;
} point;
Of 7 course people could still access _data
if they 6 would really want to (just like people can 5 access private data in C++ by adding a #define private public
before 4 their includes) but that is their own responsibility; at 3 least you have indicated that they shouldn't 2 do that if they want your library to behave 1 as it should.
I use this approach in order to let client 4 alloc the module instance in his STACK.
struct module_private {
int data;
}
typedef uint8_t module_t [sizeof (struct module_private) ];
Client 3 will be able to see private struct content, but 2 not access it without doing a cast that 1 he shouldn't.
Use the following workaround:
#include <stdio.h>
#define C_PRIVATE(T) struct T##private {
#define C_PRIVATE_END } private;
#define C_PRIV(x) ((x).private)
#define C_PRIV_REF(x) (&(x)->private)
struct T {
int a;
C_PRIVATE(T)
int x;
C_PRIVATE_END
};
int main()
{
struct T t;
struct T *tref = &t;
t.a = 1;
C_PRIV(t).x = 2;
printf("t.a = %d\nt.x = %d\n", t.a, C_PRIV(t).x);
tref->a = 3;
C_PRIV_REF(tref)->x = 4;
printf("tref->a = %d\ntref->x = %d\n", tref->a, C_PRIV_REF(tref)->x);
return 0;
}
Result is:
t.a = 1
t.x = 2
tref->a = 3
tref->x = 4
0
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.