Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making a typedef struct public for local declaration, but keep the structure member access private to the module it is defined in

I have a situation where I have a struct that I want to be able to be declared locally in other modules, but I only want the module where the struct is defined to be able to actually have any access to the members. Note this is for an embedded application so I do not have the ability to dynamically allocate memory (malloc).

foo.h

typedef struct my_struct T_my_struct;

int GetA(T_my_struct *bar);
int GetB(T_my_struct *bar);

foo.c

#include "foo.h"

struct my_struct
{
    int a;
    char b;
}

int GetA(T_my_struct *bar)
{
    return bar->a;
}

int GetB(T_my_struct *bar)
{
    return bar->b;
}

void Init(T_my_struct *bar)
{
    bar->a = 5;
    bar->b = 3;
}

bar.c:

#include "bar.h"
#include "foo.h"
#include <stdio.h>
#include <stdlib.h>

static T_my_struct local_instance;  // <--storage size of local_instance not know here

int main()
{
    Init(&local_instance);

    printf("A: %d\n", GetA(&local_instance));
}

I know I could create a local T_my_struct pointer and have it allocated in foo.c, except I do not have malloc as stated earlier. I also realize that I could just make the struct definition in foo.h; however, I do not want the other modules (i.e. bar.c) to directly access any of the members. Is there a way that I can do this in C without dynamic memory allocation?

like image 229
ryeager Avatar asked Aug 13 '15 22:08

ryeager


2 Answers

To elaborate on my comment on Matt's answer (or your response to it), this solution uses a hidden resource pool and handles rather then pointers.

foo.h

typedef int bar_handle_t ;

int getBarHandle() ;
void freeBarHandle( bar_handle_t handle ) ;
int getA( bar_handle_t handle ) ;
int getB( bar_handle_t handle ) ;

foo.c

#include <stdbool.h>
#include "foo.h"

typedef struct
{
    int a;
    char b;
} bar_t ;

typedef struct
{
    bool in_use ;
    bar_t bar ;
} bar_pool_t ;

#define HANDLE_COUNT 20
static bar_pool_t bar_pool[HANDLE_COUNT] ;

bar_handle_t getBarHandle()
{
    bar_handle_t handle ;

    for( handle = 0 ;
         bar_pool[handle].in_use && handle < HANDLE_COUNT; 
         handle++ )
    {
        // do nothing
    }

    if( handle < HANDLE_COUNT )
    {
        bar_pool[handle].in_use = true ;
        bar_pool[handle].bar.a = 5;
        bar_pool[handle].bar.a = 3;
    }
    else
    {
        handle = -1 ;
    }

    return handle ;
} 

void freeBarHandle( bar_handle_t handle )
{
    if( handle >= 0 && handle < HANDLE_COUNT )
    {
        bar_pool[handle].in_use = false ;
    }
}

int getA( bar_handle_t handle )
{
    return bar_pool[handle].bar.a ;
}

int getB( bar_handle_t handle )
{
    return bar_pool[handle].bar.b ;
}
like image 132
Clifford Avatar answered Oct 18 '22 22:10

Clifford


One approach would be to add a function to foo.h:

T_my_struct *get_bar_instance(void);

whose implementation in foo.c is:

T_my_struct *get_bar_instance(void)
{
     static T_my_struct x;
     return &x;
}

Then in bar.c you write get_bar_instance() instead of &local_instance.

If multiple files need an instance then make one function for each (or you could use a single function with integer argument).

like image 38
M.M Avatar answered Oct 18 '22 20:10

M.M