Read-only variables in C?

A

Ark

Recently there was a thread (and I believe more than one) on a theme
that a variable, say,
T foo;
is computed once and then is not modified (in the first place,
inadvertently) ever again.

The consensus was that this can only be achieved with
static T foo;
and an API-level function,
T get_foo(void) { return foo;}
or
const T *get_foop(void) {return &foo;}

[There was also an improvement to ensure foo is computed before use.]

However, I see no wrong in giving foo external linkage along with hiding
it. That is, I think the following (in an appropriate header) does the
trick:
extern T foo;
#define foo ((const T)foo)
/*the standard guarantees no recursive expansion */

When my code uses foo, it's the macro and the expression is not an
lvalue. This of course doesn't protect from malicious intent but on the
source code level it's seldom a goal.

Questions:
1. Am I missing something?
2. If not: The look of the code is pretty ugly (T appears twice and foo,
three times; there are two statements for semantically one definition).
I failed to concoct anything more elegant because I don't know of any
way to macroize a macro definition. Does anyone have a better suggestion?

Thank you,
- Ark
 
O

Old Wolf

Ark said:
Recently there was a thread (and I believe more than one) on a theme
that a variable, say,
T foo;
is computed once and then is not modified (in the first place,
inadvertently) ever again.

The consensus was that this can only be achieved with
static T foo;
and an API-level function,
T get_foo(void) { return foo;}
or
const T *get_foop(void) {return &foo;}

However, I see no wrong in giving foo external linkage along with hiding
it. That is, I think the following (in an appropriate header) does the
trick:
extern T foo;
#define foo ((const T)foo)
/*the standard guarantees no recursive expansion */

Well, then someone might use foo before it has been initialized.
The whole point of the get_foo function is to ensure that it
cannot be used before it is initialized.

My question: is it legal to have:
T foo;

and
extern const T foo;

? If so, then that is a very simple solution to your question
(ignoring the initialization problem).
 
A

Ark

Old said:
Well, then someone might use foo before it has been initialized.
The whole point of the get_foo function is to ensure that it
cannot be used before it is initialized.

My question: is it legal to have:
T foo;

and
extern const T foo;

? If so, then that is a very simple solution to your question
(ignoring the initialization problem).
It is always a good idea to have the declaration in the scope of the
definition. In this case, what you suggest is, I believe, (almost) legal
but will not do what we want: the qualifiers are accumulated from all
declarations and foo ends up being const (and so it needs an
initializer). In the opposite case it may be an UB.

I fully understand the value of access functions (which can be used for
other purposes, too, like testing the storage integrity on access); the
issue is whether read-only semantics can be expressed in C, and if so,
how ugly or elegant it can get.

Here is a safe variation on the method, now with an access function
which may be optimized out:
extern T foo;
static inline get_foo(void) { something_if_needed; return foo; }
#define foo get_foo() /* still need to hide the original foo */

Obviously this calls for C99 or C90 with common extensions.

If something_if_needed is somehow macroized (based on policy of dealing
with these RO variables), then the first two lines can be macroized,
too. So the ugliness score is about the same as of the first method. I
am still wondering if it can be improved.

- Ark
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top