Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make struct members private?

Tags:

c

struct

I define a structure in a header file like so:

typedef struct {
    void *data;
} point;

I want to keep other people from accessing *data directly, so I thought I'd declare the structure in the .c file instead and use something like extern typedef struct point; in the header file. That doesn't work however.

What's the best way to achieve this?

like image 884
ryyst Avatar asked Mar 20 '11 10:03

ryyst


People also ask

Can struct members be private?

Yes structures can have private members, you just need to use the access specifier for the same. struct Mystruct { private: m_data; }; Only difference between structure and class are: access specifier defaults to private for class and public for struct.

Can C struct have private members?

Sometimes a question arose "Can a structure has private members?" The answer is "Yes! In C++, we can declare private members in the structure". So the important thing is that "we can declare a structure just like a class with private and public members".

Are struct members public or private?

Because the only difference between a structure and a class is that structure members have public access by default and class members have private access by default, you can use the keywords class or struct to define equivalent classes.


2 Answers

In your (public) header file:

typedef struct point point;

In your .c file:

struct point
{
    void *data;
};

Note that users of your code will no longer be able to create a point on the stack, as the compiler doesn't know how big it is. You may have to provide a point_create() function which allocates memory and returns its address to the caller.

like image 166
Graham Borland Avatar answered Sep 22 '22 12:09

Graham Borland


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 which create and delete your objects which are defined here in an enum. Your methods which use the object will then need to lookup the integer handle to get the meta data object where the real data is stored. This design is not very efficient if the objects you manage are small since for every object a second object is need which stores the object type, handle value and the pointer to the real data. But you get much stronger 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 of your Api might look like this:

Handle h = CreateType(PointType);
IncrementX(h);
IncrementX(h);
PrintPoint(h);
DeleteType(h);

And there is the super secret implementation in private.cpp where the Handle lookup array and some helper 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

like image 38
Alois Kraus Avatar answered Sep 19 '22 12:09

Alois Kraus