I would like to give a module variable a read-only access for client modules. Several solutions:
1. The most common one:
// module_a.c
static int a;
int get_a(void)
{
return a;
}
// module_a.h
int get_a(void);
This makes one function per variable to share, one function call (I am thinking both execution time and readability), and one copy for every read. Assuming no optimizing linker.
2. Another solution:
// module_a.c
static int _a;
const int * const a = &_a;
// module_a.h
extern const int * const a;
// client_module.c
int read_variable = *a;
*a = 5; // error: variable is read-only
I like that, besides the fact that the client needs to read the content of a pointer. Also, every read-only variable needs its extern const
pointer to const
.
3. A third solution, inspired by the second one, is to hide the variables behind a struct and an extern pointer to struct. The notation module_name->a
is more readable in the client module, in my opinion.
4. I could create an inline definition for the get_a(void)
function. It would still look like a function call in the client module, but the optimization should take place.
My questions:
Is there a best way to make variables modified in a module accessible as read-only in other modules? Best in what aspect?
Which solutions above would you accept or refuse to use, and why?
I am aware that this is microoptimization - I might not implement it - but I am still interested in the possibility, and above all in the knowing.
For speed identical to variable access, you can define an extern variable inside an inline function:
static inline int get_a(void)
{
extern int a_var;
return a_var;
}
This is simple and clear to read. The other options seem unnecessarily convoluted.
Edit: I'm assuming that you use prefixes for your names, since you write C. So it will actually be:
extern int my_project_a;
This prevents a client from accidentally making a variable with the same name. However, what if a client makes a variable with the same name on purpose? In this situation, you have already lost, because the client is either 1) actively trying to sabotage your library or 2) incompetent beyond reasonable accommodation. In situation #1, there is nothing you can do to stop the programmer. In situation #2, the program will be broken anyway.
Try running nm /lib/libc.so
or equivalent on your system. You'll see that most libc
implementations have several variables that are not defined in header files. On my system this includes things like __host_byaddr_cache
. It's not the responsibility of the C library implementors to babysit me and prevent me from running:
extern void *__host_byaddr_cache;
__host_byaddr_cache = NULL;
If you start down the path of thinking that you have to force clients to treat your variable as read-only, you are heading down the path of fruitless paranoia. The static
keyword is really just a convenience to keep objects out of the global namespace, it is not and never was a security measure to prevent external access.
The only way to enforce read-only variables is to manage the client code — either by sandboxing it in a VM or by algorithmically verifying that it can't modify your variable.
Concerning option #4, I'm not sure you can make it inline if the variable isn't accessible outside the implementation file. I wouldn't count options #2 and #3 as truly read-only. The pointer can have the constness cast away and be modified (const is just a compiler "warning", nothing concrete). Only option #1 is read-only because it returns a copy.
- The most common one:
There's a reason why it's the most common one. It's the best one.
I don't regard the performance hit to be significant enough to be worth worrying about in most situations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With