Does it make any sense to make struct immutable? - c

Since I came to C from higher level Java where we don't have type quialifiers like const in order to make a type immutable we have to declare all its members final and be sure the members are immutable by themselves.
By contract, in C we have type quialifier const.
To be more specific, let me provide an example I'm currently stuck with. I have the following
application.h:
struct application_config_t{
int poll_interval;
int compression_ratio;
//other config parameters
};
struct application_t{ //This structure make me confused
void (*run_application)(struct application_t*);
void (*stop_application)(struct application_t*);
};
struct application_t* create_app(const struct application_config_t);
void release_app(struct application_t*);
I'm not sure about how to define application_t structure. Its only purpose is to do the actaul run with run_application and to handle SIGINT with stop_application to perform graceful shutdown and then after stop_application returns to call release_app(struct application_t*) to free the memory.
I have the following case to choose:
I. Immutable application_t
struct application_t{
void (*const run_application)(struct application_t*);
void (*const stop_application)(struct application_t*);
}
I think this is fine because once created an application should not be modified. But creation of such an immutable structure will entail memcpy call anyway...
II. Mutable application_t while create application will be declared as
const struct application_t* create_app(const struct application_config_t);
This would be fine, but I want to release the memory pointed to by struct application_t* after stop_application returns. Releasing struct application_t* means that appliaction_t is not really const. And usage like
struct application_config_t cfg;
//...
const struct application_t *app_ptr = create_app(cfg);
(app_ptr -> run_application)(app_ptr);
release_app((struct application_t *) app_ptr); //const cast
would require cast against constness.

Releasing struct application_t* means that appliaction is not really const
Actually it is. The client code could not mutate it, and should not be using it further after handing it over to release_app anyway. It is const throughout its lifetime, and if release_app accepts by a pointer to const, it will be semantically correct (just do the cast inside release_app).
Why do I say it will be semantically correct? Because when create_app allocates space for the structure and initializes it, it isn't const in there, is it? The const is added later as part of a contract. So accepting a const pointer in release_app is just following the same contract you already established. The fact the API pair knows the storage can be mutated doesn't break the contract.

Related

Trying to avoid showing private attributes in a header without pimpl

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.

Memory architecture with self reference structure in C

I have a structure named container.
This structure has a pointer of type void named obj_mem, which will point to some allocated memory.
As this memory has to be able to hold different structure, I keep track of the adress and the type of each element it contains(adress_obj, type_obj) for access and casting.
The last property my container struct is that it has a self reference child.
So at running time, the user can create children of a container and add object to them.
typedef enum tob{ //type of object
obj1, obj2, obj3, obj4 ...
}t_tob;
typedef struct obj1{
//declare some stuff
}t_obj1;
typedef struct obj2{
//declare some stuff
}t_obj2;
typedef struct obj3{
//declare some stuff
}t_obj3;
typedef struct obj4{
//declare some stuff
}t_obj4;
typedef struct container{
int name_size;
char* name;
int nmbr_obj;
t_tob* type_obj;
char* adress_obj;
void* mem_obj;
int nmbr_child;
struct container* child;
}t_container;
Then I have a function which process the whole data:
It process the object in the obj_mem of a container.
Then iterate through his children and process their object.
Then iterate through the children of his children and process their
object
ect ... Until the end of the tree.
The problem:
I'm pretty new to programming and I'm not sure it's the right way to do this.
This code will lead to a lot of malloc call, so the memory won't be contiguous, is this a problem ?
Is there any more elegant way of doing this dynamic type of things ?
Do you have any books who could help me learning more on this kind of memory architecture ?
I'm sorry if this post can look a bit blurry but this is how I feel right now.
Thanks for thelp.
the memory won't be contiguous, is this a problem ?
It isn't a problem, but it will hurt performance.
Using better memory locality (continuous memory rather than fragmented memory) helps the CPU utilize it's cache and minimizes cache misses, which can be a very big thing where performance is concerned.
But this isn't really the most important part. You can always optimize this a little later. The most important part is that the data structure actually does what it needs to do.
Is there any more elegant way of doing this dynamic type of things ?
Probably, but I'm not sure what you want to do, so I can't help you.
Normally when writing a dynamic type system, the type of an object is part of the object, i.e.:
struct my_object_s {
unsigned int type;
/* common type data*/
struct vtable_s * vtable;
};
struct my_string_s {
struct my_object_s header;
size_t len;
char str[];
}
This allows an object to be independent from it's container.
Do you have any books who could help me learning more on this kind of memory architecture ?
I read most of what I know on the internet (I do have a few books, but not many of them go into hardware architecture).
EDIT (answer to comment)
You can find far more comprehensive information about Object Oriented Programming with C here. The author has done extensive work explaining the concepts and these same ideas are often used (in part or in whole) when authoring dynamic types.
For example, by having a virtual function table, casting can be avoided entirely.
On the other hand, it's common to use a switch statement when you have a limited set of types.
enum my_type_enum {
/** A simple flag object object (`my_object_s`) for NULL. */
MY_NULL,
/** A simple flag object (`my_object_s`) for OK. */
MY_OK,
/** A simple flag object (`my_err_s`) that indicates an error. */
MY_ERR,
/** A Number object object (`my_number_s`). */
MY_NUMBER,
/** A String object (`my_string_s`). */
MY_STRING,
/** An Array object object (`my_array_s`). */
MY_ARRAY,
};
typedef struct { enum my_type_enum type; } my_object_s;
typedef struct {
my_object_s header;
size_t len;
char str[];
} my_string_s;
void example_usage(my_object_s *obj) {
switch (obj->type) {
case MY_STRING:
printf("String: %s", ((my_string_s *)obj)->str);
break;
default:
printf("whatever...");
}
}
Notice that by having my_object_s as the header for each one of the types, you can safely access the header data as if any pointer to an object was a my_object_s * and this way you can discern it's underlying type.
If your container has to hold a data tree such a structure is pretty much required in some form. The one thing that really seemed odd is that your type of object member is a pointer, that would usually be a simple value.

Initializing a const array inside a struct

#define LENGTH 6
typedef char data_t[LENGTH];
struct foo {
const data_t data;
...
}
...
void bar(data_t data) {
printf("%.6s\n", data);
struct foo myfoo = {*data};
printf("%.6s\n", foo.data);
}
I'm trying to have this struct which holds directly the data I'm interested in, sizeof(foo) == 6+the rest, not sizeof(foo) == sizeof(void*)+the rest. However I can't find a way to initialize a struct of type foo with a data_t. I think maybe I could remove the const modifier from the field and use memcpy but I like the extra safety and clarity.
I don't get any compile errors but when I run the code I get
123456
1??
so the copy didn't work properly I think.
This is for an arduino (or similar device) so I'm trying to keep it to very portable code.
Is it just not possible ?
EDIT: removing the const modifier on the data_t field doesn't seem to help.
It is possible to do this, for some cost >=0.
typedef struct
{
char c[LENGTH];
} data_t; // this struct is freely copyable
struct foo
{
const data_t data; // but this data member is not
int what;
};
void foo (char* x) {
data_t d; // declare freely copyable struct instance
memcpy(d.c, x, sizeof(d.c)); // memcpy it
struct foo foo = { d, 42 }; // initialise struct instance with const member
...
};
Some compilers (e.g. clang) are even able to optimise away the redundant copying (from x to d.c and then from d to foo.data ⇒ from x straight to foo.data). Others (gcc I'm looking at you) don't seem to be able to achieve this.
If you pass around pointers to data_t rather than straight char pointers, you won't need this additional memcpy step. OTOH in order to access the char array inside foo you need another level of member access (.data.c instead of just .data; this has no runtime cost though).
It's impossible to do it in a standard compliant way.
Due to its being const, const char data[6]; must be initialized to be usable, and it may only be initialized statically (static objects with no initializer get automatically zeroed), with a string literal, or with a brace-enclosed initializer list. You cannot initialize it with a pointer or another array.
If I were you, I would get rid of the const, document that .data shouldn't be changed post-initialization, and then use memcpy to initialize it.
(const on struct members doesn't work very well in my opinion. It effectively prevents you from being able to have initializer functions, and while C++ gets around the problem a little bit by having special language support for its constructor functions, the problem still remains if the const members are arrays).

How can a destination buffer be opaque?

I came across implementation details of serialization functions and it is mentioned that the target memory to which the structure has to be unpacked and stored needed to be an opaque buffer.
Wikipedia says:
"Some languages, such as C, allow the declaration of opaque records (structs), whose size and fields are hidden from the client. The only thing that the client can do with an object of such a type is to take its memory address, to produce an opaque pointer."
According to this pointer to any memory address would be opaque since we have no control over the memory address at which the destination buffer would start.
So what is the point of such a classification in C with respect to buffers. I have seen that in C++ objects can be opaque which makes more sense, since we can create objects which can be prevented from changing and data abstraction is in place .
Suppose you had a library header that looks like this:
struct lib_data;
struct lib_data *new_data();
void read_data(struct lib_data *data);
void clean_data(struct lib_data *data);
There is a forward declaration of struct lib_data without specifying its contents. Your app can then do this:
struct lib_data *data = new_data();
read_data(data);
clean_data(data);
Note that you have no knowledge of what struct lib_data looks like or even what its size is. That is what is meant by opaque. But you can hold a pointer to it and pass that around.
In the library's implementation (which you may or may not have access to), the struct has a proper definition and can therefore modify its elements.
For example, the library implementation might look like this:
struct lib_data {
int data1
double data2;
}
struct lib_data *new_data()
{
struct lib_data *temp = malloc(sizeof(struct lib_data);
temp->data1 = 1;
temp->data2 = 3.5;
return temp;
}
void read_data(struct lib_data *data)
{
...
}
void clean_data(struct lib_data *data)
{
free(data);
}
So the library can manipulate the struct, but application that use it cannot.

Defining a struct with a pointer

I'm relatively new to C and trying to understand structs and pointers. What does the *Building at the end of this struct declaration do?
typedef struct building {
char *floor;
struct building *nextBuilding;
} *Building;
Does it mean that from now on when I do
Building someBuilding = malloc(sizeof(struct building));
somebuilding is a pointer to a building?
Yes, when you write:
typedef struct building { … } *Building;
Building bp;
then bp is a pointer to a struct building. However, it is frequently regarded as bad style to include the pointer in the typedef; code is easier to understand if you use:
typedef struct building { … } Building;
Building *bp;
Now it is clear looking at the definition of bp that the type is a pointer. If you are never going to access the internals of the structure, then it doesn't matter too much (but look at FILE * in <stdio.h>; you always write FILE *fp, etc). If you're going to access the internals:
printf("Floor: %s\n", bp->floor);
then it is better to have the pointer visible. People will be mildly surprised to see Building bp; and then later bp->floor instead of bp.floor.
To answer the question: yes. You now have a type Building that is a pointer to a struct building and you can do this:
Building someBuilding = malloc(sizeof(struct building));
someBuilding->floor = malloc (sizeof(char)*20);
strcpy(someBuilding->floor, "First floor");
someBuilding->nextBuilding = NULL;
etc.
note that this might not be a good idea in all cases. For example if you declare a method:
void setFloorName(Building building, char* name)
you can't really tell that you need to pass a pointer to a building struct, but if you do:
void setFloorName(Building* building, char* name)
you immediately see that the function takes a pointer.

Resources