Trying to avoid showing private attributes in a header without pimpl - c

I consider my header file to be an interface of my module. I really dislike showing my users things they don't need to see in my interface.
The C folks do that by predeclaring structs and having the functions pass around pointers to that struct.
Which is perfect, except when there is a part of the struct that is public. My users need to be able to access it and modify it freely.
One solution is to do setters and getters and pass a pointer to the struct to which we don't show a definition.
We could also do like the c++ pimpl thing where we would have a pointer to an internal struct in our external struct. Again showing stuff in the interface that we shouldn't be showing.
And then I have an idea. And I want your input. Tell me if you think it's good or bad.
thing.h:
/// Must use thing_init() or bad will happen
struct thing
{
int public_attribute;
};
typedef struct thing thing;
thing*
thing_init();
thing.c:
struct internal
{
int private_attribute;
};
typedef struct internal internal;
thing*
thing_init()
{
void* mem = malloc(sizeof(internal) + sizeof(thing));
internal* i = (internal*)mem;
thing* t = (thing*)(mem + sizeof(internal));
// Initialize stuff
return t;
}
Sooo the idea is like how malloc does things basically. What could go wrong here?

Your approach is broken. For example should the public part have a double and the private part just a char, the arithmetic would cause the the public part to be misaligned.
What you can use and should use is the common initial prefix:
struct thing {
int public_attribute;
};
struct internal {
struct thing public;
int private_attribute;
};
struct thing *thing_init()
{
struct internal *mem = malloc(sizeof(struct internal));
internal->public->public_attribute = 6 * 9;
internal->private_attribute = 42;
return &interal->public;
// or
return (struct thing *)internal;
}
I.e. the public part is the first member of the entire structure. This technique is well-defined in C.
Then in all functions that get in struct thing * you cast this pointer to struct internal *, and are ready to use the public and private members.
This technique is used e.g. by the CPython interpreter, where all Python objects in C code share a common initial sequence of PyObject followed by private parts.

Related

Getter function to return values of a struct in c

I'm practicing c and I want to return data of a struct to access it within an other location.
Let's say I have something like this:
typedef struct
{
int8 x;
u64 y;
u32 z;
} myData_t;
myData_t myData_g;
/*Setter*/
void WritemyData(const myData_t* data)
{
myData_g = *data;
}
How can I return the data which are stored within a global variable to be read within an other location. Can I not just do something like:
/*Getter*/
myData_t GettmyData(void)
{
return myData_g;
}
Would be thankful for any information!
First of all, for things like this consider making the "global" a private variable instead, by adding static myData_t myData_g;. Now nobody outside this .c file can access it intentionally/by accident.
As for your function GettmyData, it will work fine. However, passing/returning structs by value is considered bad practice since it involves making a full copy of the struct on the stack, which may be slow and take up unnecessary memory temporarily.
This might be better idea might be:
void get_my_data (myData_t* obj)
{
*obj = myData_g;
}
Here you have to document that the caller should allocate the variable pointed at by obj on the caller side.

Data encapsulation in C

I am currently working on an embedded system and I have a component on a board which appears two times. I would like to have one .c and one .h file for the component.
I have the following code:
typedef struct {
uint32_t pin_reset;
uint32_t pin_drdy;
uint32_t pin_start;
volatile avr32_spi_t *spi_module;
uint8_t cs_id;
} ads1248_options_t;
Those are all hardware settings. I create two instances of this struct (one for each part).
Now I need to keep an array of values in the background. E.g. I can read values from that device every second and I want to keep the last 100 values. I would like this data to be non-accessible from the "outside" of my component (only through special functions in my component).
I am unsure on how to proceed here. Do I really need to make the array part of my struct? What I thought of would be to do the following:
int32_t *adc_values; // <-- Add this to struct
int32_t *adc_value_buffer = malloc(sizeof(int32_t) * 100); // <-- Call in initialize function, this will never be freed on purpose
Yet, I will then be able to access my int32_t pointer from everywhere in my code (also from outside my component) which I do not like.
Is this the only way to do it? Do you know of a better way?
Thanks.
For the specific case of writing hardware drivers for a microcontroller, which this appears to be, please consider doing like this.
Otherwise, use opaque/incomplete type. You'd be surprised to learn how shockingly few C programmers there are who know how to actually implement 100% private encapsulation of custom types. This is why there's some persistent myth about C lacking the OO feature known as private encapsulation. This myth originates from lack of C knowledge and nothing else.
This is how it goes:
ads1248.h
typedef struct ads1248_options_t ads1248_options_t; // incomplete/opaque type
ads1248_options_t* ads1248_init (parameters); // a "constructor"
void ads1248_destroy (ads1248_options_t* ads); // a "destructor"
ads1248.c
#include "ads1248.h"
struct ads1248_options_t {
uint32_t pin_reset;
uint32_t pin_drdy;
uint32_t pin_start;
volatile avr32_spi_t *spi_module;
uint8_t cs_id;
};
ads1248_options_t* ads1248_init (parameters)
{
ads1248_options_t* ads = malloc(sizeof(ads1248_options_t));
// do things with ads based on parameters
return ads;
}
void ads1248_destroy (ads1248_options_t* ads)
{
free(ads);
}
main.c
#include "ads1248.h"
int main()
{
ads1248_options_t* ads = ads1248_init(parameters);
...
ads1248_destroy(ads);
}
Now the code in main cannot access any of the struct members, all members are 100% private. It can only create a pointer to a struct object, not an instance of it. Works exactly like abstract base classes in C++, if you are familiar with that. The only difference is that you'll have to call the init/destroy functions manually, rather than using true constructors/destructors.
It's common that structures in C are defined completely in the header, although they're totally opaque (FILE, for example), or only have some of their fields specified in the documentation.
C lacks private to prevent accidental access, but I consider this a minor problem: If a field isn't mentioned in the spec, why should someone try to access it? Have you ever accidentally accessed a member of a FILE? (It's probably better not to do things like having a published member foo and a non-published fooo which can easily be accessed by a small typo.) Some use conventions like giving them "unusual" names, for example, having a trailing underscore on private members.
Another way is the PIMPL idiom: Forward-declare the structure as an incomplete type and provide the complete declaration in the implementation file only. This may complicate debugging, and may have performance penalties due to less possibilities for inlining and an additional indirection, though this may be solvable with link-time optimization. A combination of both is also possible, declaring the public fields in the header along with a pointer to an incomplete structure type holding the private fields.
I would like this data to be non-accessible from the "outside" of my
component (only through special functions in my component).
You can do it in this way (a big malloc including the data):
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef struct {
uint32_t pin_reset;
uint32_t pin_drdy;
uint32_t pin_start;
volatile avr32_spi_t *spi_module;
uint8_t cs_id;
} ads1248_options_t;
void fn(ads1248_options_t *x)
{
int32_t *values = (int32_t *)(x + 1);
/* values are not accesible via a member of the struct */
values[0] = 10;
printf("%d\n", values[0]);
}
int main(void)
{
ads1248_options_t *x = malloc(sizeof(*x) + (sizeof(int32_t) * 100));
fn(x);
free(x);
return 0;
}
You could make a portion of your structure private like this.
object.h
struct object_public {
uint32_t public_item1;
uint32_t public_item2;
};
object.c
struct object {
struct object_public public;
uint32_t private_item1;
uint32_t *private_ptr;
}
A pointer to an object can be cast to a pointer to object_public because object_public is the first item in struct object. So the code outside of object.c will reference the object through a pointer to object_public. While the code within object.c references the object through a pointer to object. Only the code within object.c will know about the private members.
The program should not define or allocate an instance object_public because that instance won't have the private stuff appended to it.
The technique of including a struct as the first item in another struct is really a way for implementing single inheritance in C. I don't recall ever using it like this for encapsulation. But I thought I would throw the idea out there.
You can:
Make your whole ads1248_options_t an opaque type (as already discussed in other answers)
Make just the adc_values member an opaque type, like:
// in the header(.h)
typedef struct adc_values adc_values_t;
// in the code (.c)
struct adc_values {
int32_t *values;
};
Have a static array of array of values "parallel" to your ads1248_options_t and provide functions to access them. Like:
// in the header (.h)
int32_t get_adc_value(int id, int value_idx);
// in the code (.c)
static int32_t values[MAX_ADS][MAX_VALUES];
// or
static int32_t *values[MAX_ADS]; // malloc()-ate members somewhere
int32_t get_adc_value(int id, int value_idx) {
return values[id][value_idx]
}
If the user doesn't know the index to use, keep an index (id) in your ads1248_options_t.
Instead of a static array, you may provide some other way of allocating the value arrays "in parallel", but, again, need a way to identify which array belongs to which ADC, where its id is the simplest solution.

What does the code below mean, in regards to structs in C?

I'm really new to C programming and I'm still trying to understand the concept of using pointers and using typedef structs.
I have this code snippet below that I need to use in a program:
typedef struct
{
char* firstName;
char* lastName;
int id;
float mark;
}* pStudentRecord;
I'm not exactly sure what this does - to me it seems similar as using interfaces in Objective-C, but I don't think that's the case.
And then I have this line
pStudentRecord* g_ppRecords;
I basically need to add several pStudentRecord to g_ppRecords based on a number. I understand how to create and allocate memory for an object of type pStudentRecord, but I'm not sure how to actually add multiple objects to g_ppRecords.
defines a pointer to the struct described within the curly bracers, here is a simpler example
typedef struct {
int x;
int y;
}Point,* pPoint;
int main(void) {
Point point = {4,5};
pPoint point_ptr = &point;
printf("%d - %d\n",point.x,point_ptr->x);
pPoint second_point_ptr = malloc(sizeof(Point));
second_point_ptr->x = 5;
free(second_point_ptr);
}
The first declares an unnamed struct, and a type pStudentRecord that is a pointer to it. The second declares g_ppRecords to be a pointer to a pStudentRecord. In other words, a pointer to a pointer to a struct.
It's probably easier to think of the second as an "array of pointers". As such, g_ppRecords[0] may point to a pStudentRecord and g_ppRecords[1] to another one. (Which, in turn, point to a record struct.)
In order to add to it, you will need to know how it stores the pointers, that is, how one might tell how many pointers are stored in it. There either is a size somewhere, which for size N, means at least N * sizeof(pStudentRecord*) of memory is allocated, and g_ppRecords[0] through g_ppRecords[N-1] hold the N items. Or, it's NULL terminated, which for size N, means at least (N+1) * sizeof(pStudentRecord*) of memory is allocated and g_ppRecords[0] through g_ppRecords[N-1] hold the N items, and g_ppRecords[N] holds NULL, marking the end of the string.
After this, it should be straightforward to create or add to a g_ppRecords.
A struct is a compound data type, meaning that it's a variable which contains other variables. You're familiar with Objective C, so you might think of it as being a tiny bit like a 'data only' class; that is, a class with no methods. It's a way to store related information together that you can pass around as a single unit.
Typedef is a way for you to name your own data types as synonyms for the built-in types in C. It makes code more readable and allows the compiler to catch more errors (you're effectively teaching the compiler more about your program's intent.) The classic example is
typedef int BOOL;
(There's no built-in BOOL type in older ANSI C.)
This means you can now do things like:
BOOL state = 1;
and declare functions that take BOOL parameters, then have the compiler make sure you're passing BOOLs even though they're really just ints:
void flipSwitch(BOOL isOn); /* function declaration */
...
int value = 0;
BOOL boolValue = 1;
flipSwitch(value); /* Compiler will error here */
flipSwitch(boolValue); /* But this is OK */
So your typedef above is creating a synonym for a student record struct, so you can pass around student records without having to call them struct StudentRecord every time. It makes for cleaner and more readable code. Except that there's more to it here, in your example. What I've just described is:
typedef struct {
char * firstName;
char * lastName;
int id;
float mark;
} StudentRecord;
You can now do things like:
StudentRecord aStudent = { "Angus\n", "Young\n", 1, 4.0 };
or
void writeToParents(StudentRecord student) {
...
}
But you've got a * after the typedef. That's because you want to typedef a data type which holds a pointer to a StudentRecord, not typedef the StudentRecord itself. Eh? Read on...
You need this pointer to StudentRecord because if you want to pass StudentRecords around and be able to modify their member variables, you need to pass around pointers to them, not the variables themselves. typedefs are great for this because, again, the compiler can catch subtle errors. Above we made writeToParents which just reads the contents of the StudentRecord. Say we want to change their grade; we can't set up a function with a simple StudentRecord parameter because we can't change the members directly. So, we need a pointer:
void changeGrade(StudentRecord *student, float newGrade) {
student->mark = newGrade;
}
Easy to see that you might miss the *, so instead, typedef a pointer type for StudentRecord and the compiler will help:
typedef struct { /* as above */ } *PStudentRecord;
Now:
void changeGrade(PStudentRecord student, float newGrade) {
student->mark = newGrade;
}
It's more common to declare both at the same time:
typedef struct {
/* Members */
} StudentRecord, *PStudentRecord;
This gives you both the plain struct typedef and a pointer typedef too.
What's a pointer, then? A variable which holds the address in memory of another variable. Sounds simple; it is, on the face of it, but it gets very subtle and involved very quickly. Try this tutorial
This defines the name of a pointer to the structure but not a name for the structure itself.
Try changing to:
typedef struct
{
char* firstName;
char* lastName;
int id;
float mark;
} StudentRecord;
StudentRecord foo;
StudentRecord *pfoo = &foo;

Modular data structure in C with dynamic data type

For my upcoming university C project, I'm requested to have modular code as C allows it. Basically, I'll have .c file and a corresponding .h file for some data structure, like a linked list, binary tree, hash table, whatever...
Using a linked list as an example, I have this:
typedef struct sLinkedList {
int value;
struct sLinkedList *next;
} List;
But this forces value to be of type int and the user using this linked list library would be forced to directly change the source code of the library. I want to avoid that, I want to avoid the need to change the library, to make the code as modular as possible.
My project may need to use a linked list for a list of integers, or maybe a list of some structure. But I'm not going to duplicate the library files/code and change the code accordingly.
How can I solve this?
Unfortunately, there is no simple way to solve this. The most common, pure C approach to this type of situation is to use a void*, and to copy the value into memory allocated by you into the pointer. This makes usage tricky, though, and is very error prone.
Another alternative no one has mentioned yet can be found in the Linux kernel's list.h generic linked list implementation. The principle is this:
/* generic definition */
struct list {
strict list *next, *prev;
};
// some more code
/* specific version */
struct intlist {
struct list list;
int i;
};
If you make struct intlist* pointers, they can safely be cast (in C) to struct list* pointers, thus allowing you to write genericized functions that operate on struct list* and have them work regardless of datatype.
The list.h implementation uses some macro trickery to support arbitrary placement of the struct list inside your specific list, but I prefer to rely on the struct-cast-to-first-member trick myself. It makes the calling code much easier to read. Granted, it disables "multiple inheritance" (assuming you consider this to be some kind of inheritance) but next(mylist) looks nicer than next(mylist, list). Plus, if you can avoid delving into offsetof hackery, you're probably going to end up in better shape.
Since this is a university project, we can't just give you the answer. Instead, I'd invite you to meditate on two C features: the void pointer (which you've likely encountered before), and the token pasting operator (which you may not have).
You can avoid this by defining value as void* value;. You can assign a pointer to any type of data this way, but the calling code is required to cast and dereference the pointer to the correct type. One way to keep track of this would be to add a short char array to the struct to note the type name.
This problem is precisely the reason why templates were developed for C++. The approach I've used once or twice in C is to have the value field be a void*, and cast the values thereto on insertion and cast them back on retrieval. This is far from type-safe, of course. For extra modularity, I might write insert_int(), get_mystruct() etc. functions for each type you use this for, and do the casting there.
You can use Void* instead of int. This allows the data to be of any type. But the user should be aware of the type of data.
For that, optionally you can have another member which represents Type. which is of enum {INT,CHAR,float...}
Unlike C++ where one can use template, void * is the de-facto C solution.
Also, you can put the elements of the linked list in a separate struct, e.g:
typedef struct sLinkedListElem {
int value; /* or "void * value" */
} ListElem;
typedef struct sLinkedList {
ListElem data;
struct sLinkedList *next;
} List;
so that the elements can be changed without affecting the link-ing code.
Here is an example of linked list utilities in C:
struct Single_List_Node
{
struct Single_List * p_next;
void * p_data;
};
struct Double_List_Node
{
struct Double_List * p_next;
struct Double_List * p_prev; // pointer to previous node
void * p_data;
};
struct Single_List_Data_Type
{
size_t size; // Number of elements in list
struct Single_List_Node * p_first_node;
struct Single_List_Node * p_last_node; // To make appending faster.
};
Some generic functions:
void Single_List_Create(struct Single_List_Data_Type * p_list)
{
if (p_list)
{
p_list->size = 0;
p_list->first_node = 0;
p_list->last_node = p_list->first_node;
}
return;
}
void Single_List_Append(struct Single_List_Data_Type * p_list,
void * p_data)
{
if (p_list)
{
struct Single_List_Node * p_new_node = malloc(sizeof(struct Single_List_Node));
if (p_new_node)
{
p_new_node->p_data = p_data;
p_new_node->p_next = 0;
if (p_list->last_node)
{
p_list->last_node->p_next = p_new_node;
}
else
{
if (p_list->first_node == 0)
{
p_list->first_node = p_new_node;
p_list->last_node = p_new_node;
}
else
{
struct Single_List_Node * p_last_node = 0;
p_last_node = p_list->first_node;
while (p_last_node->p_next)
{
p_last_node = p_last_node->p_next;
}
p_list->last_node->p_next = p_new_node;
p_list->last_node = p_new_node;
}
}
++(p_list->size);
}
}
return;
}
You can put all these functions into a single source file and the function declarations into a header file. This will allow you to use the functions with other programs and not have to recompile all the time. The void * for the pointer to data will allow you to use the list with many different data types.
(The above code comes as-is and has not been tested with any compiler. The responsibility of bug fixing is up to the user of the examples.)

How can I hide the declaration of a struct in C?

In the question Why should we typedef a struct so often in C?, unwind answered that:
In this latter case, you cannot return
the Point by value, since its
declaration is hidden from users of
the header file. This is a technique
used widely in GTK+, for instance.
How is declaration hiding accomplished? Why can't I return the Point by value?
ADD:
I understood why I can't return the struct by value, but, is still hard to see why i can't deference this point in my function. i.e. If my struct have member named y, why i can't do it?
pointer_to_struct->y = some_value;
Why should I use methods to do it? (Like Gtk+)
Thanks guys, and sorry for my bad english again.
Have a look at this example of a library, using a public header file, a private header file and an implementation file.
In file public.h:
struct Point;
struct Point* getSomePoint();
In file private.h:
struct Point
{
int x;
int y;
}
In file private.c:
struct Point* getSomePoint()
{
/* ... */
}
If you compile these three files into a library, you only give public.h and the library object file to the consumer of the library.
getSomePoint has to return a pointer to Point, because public.h does not define the size of Point, only that is a struct and that it exists. Consumers of the library can use pointers to Point, but can not access the members or copy it around, because they do not know the size of the structure.
Regarding your further question:
You can not dereference because the program using the library does only have the information from private.h, that does not contain the member declarations. It therefore can not access the members of the point structure.
You can see this as the encapsulation feature of C, just like you would declare the data members of a C++ class as private.
What he means is that you cannot return the struct by-value in the header, because for that, the struct must be completely declared. But that happens in the C file (the declaration that makes X a complete type is "hidden" in the C file, and not exposed into the header), in his example. The following declares only an incomplete type, if that's the first declaration of the struct
struct X;
Then, you can declare the function
struct X f(void);
But you cannot define the function, because you cannot create a variable of that type, and much less so return it (its size is not known).
struct X f(void) { // <- error here
// ...
}
The error happens because "x" is still incomplete. Now, if you only include the header with the incomplete declaration in it, then you cannot call that function, because the expression of the function call would yield an incomplete type, which is forbidden to happen.
If you were to provide a declaration of the complete type struct X in between, it would be valid
struct X;
struct X f(void);
// ...
struct X { int data; };
struct X f(void) { // valid now: struct X is a complete type
// ...
}
This would apply to the way using typedef too: They both name the same, (possibly incomplete) type. One time using an ordinary identifier X, and another time using a tag struct X.
In the header file:
typedef struct _point * Point;
After the compiler sees this it knows:
There is a struct called _point.
There is a pointer type Point that can refer to a struct _point.
The compiler does not know:
What the struct _point looks like.
What members struct _point contains.
How big struct _point is.
Not only does the compiler not know it - we as programmers don't know it either. This means we can't write code that depends on those properties of struct _point, which means that our code may be more portable.
Given the above code, you can write functions like:
Point f() {
....
}
because Point is a pointer and struct pointers are all the same size and the compiler doesn't need to know anything else about them. But you can't write a function that returns by value:
struct _point f() {
....
}
because the compiler does not know anything about struct _point, specifically its size, which it needs in order to construct the return value.
Thus, we can only refer to struct _point via the Point type, which is really a pointer. This is why Standard C has types like FILE, which can only be accessed via a pointer - you can't create a FILE structure instance in your code.
Old question, better answer:
In Header File:
typedef struct _Point Point;
In C File:
struct _Point
{
int X;
int Y;
};
What that post means is: If you see the header
typedef struct _Point Point;
Point * point_new(int x, int y);
then you don't know the implementation details of Point.
As an alternative to using opaque pointers (as others have mentioned), you can instead return an opaque bag of bytes if you want to avoid using heap memory:
// In public.h:
struct Point
{
uint8_t data[SIZEOF_POINT]; // make sure this size is correct!
};
void MakePoint(struct Point *p);
// In private.h:
struct Point
{
int x, y, z;
};
void MakePoint(struct Point *p);
// In private.c:
void MakePoint(struct Point *p)
{
p->x = 1;
p->y = 2;
p->z = 3;
}
Then, you can create instances of the struct on the stack in client code, but the client doesn't know what's in it -- all it knows is that it's a blob of bytes with a given size. Of course, it can still access the data if it can guess the offsets and data types of the members, but then again you have the same problem with opaque pointers (though clients don't know the object size in that case).
For example, the various structs used in the pthreads library use structs of opaque bytes for types like pthread_t, pthread_cond_t, etc. -- you can still create instances of those on the stack (and you usually do), but you have no idea what's in them. Just take a peek into your /usr/include/pthreads.h and the various files it includes.

Resources