By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,218 Members | 1,195 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,218 IT Pros & Developers. It's quick & easy.

A better solution? De-Const'ing a variable

P: n/a
I have some code, and I want to make it future-resistant. I have a bunch of
variables that are set up run-time, and once set up, should act as
constants. I don't want to #define them, because their values are determined
during the execution of the initialization routines, so I made them const
(I'd rather making it hard for a dev to accidentally overwrite the values).
The problem is, they are being set run-time by the return of a function
call. Right now my solution is ugly, and required me to turn a .c file to a
..cpp file. Any suggestions on how to do this in a better manner? I couldn't
find it via google or my reference books.

Basically I'm trying to make a variable non-const for one statement.

ex:
in the .h
extern const type_id CHAR_TYPE;

in the .cpp which I'd rather be a .c
const type_id CHAR_TYPE;
/*...*/
void mylib_init()
{
/*note the addressing and deadressing ops, const_cast requries pointers
to work...*/
*(const_cast<type_id*>(&CHAR_TYPE)) = ctypeless_register(sizeof(char),
NULL, NULL, "char");
}
so, if you are like me, you see heaploads of problems with my solution. Any
suggestions for a fix that is (a) less ugly, (b) doesn't require the use of
C++, and (c) makes sure people who use the code get warnings/errors if they
try to change the values of these variables.

Thanks,
-Jim Stapleton
Jul 15 '08 #1
Share this Question
Share on Google+
13 Replies


P: n/a
S James S Stapleton wrote:
I have some code, and I want to make it future-resistant. I have a bunch of
variables that are set up run-time, and once set up, should act as
constants. I don't want to #define them, because their values are determined
during the execution of the initialization routines, so I made them const
(I'd rather making it hard for a dev to accidentally overwrite the values).
The problem is, they are being set run-time by the return of a function
call. Right now my solution is ugly, and required me to turn a .c file to a
.cpp file. Any suggestions on how to do this in a better manner? I couldn't
find it via google or my reference books.

Basically I'm trying to make a variable non-const for one statement.
[...]
Two approaches I've seen used for "final" global variables:

/* foo.h */
int getGlobal(void);
#define global getGlobal()

/* foo.c */
#include "foo.h"
static int actualGlobal;
void init_foo(void) {
actualGlobal = whatever;
}
int getGlobal(void) {
return actualGlobal;
}

The other may be a hair more efficient, but is also a touch
less bullet-proof:

/* foo.h */
extern const int * const globalPtr;
#define global (*globalPtr)

/* foo.c */
#include "foo.h"
static int actualGlobal;
const int * const globalPtr = &actualGlobal;
void init_foo(void) {
actualGlobal = whatever;
}

--
Er*********@sun.com
Jul 15 '08 #2

P: n/a
>
Two approaches I've seen used for "final" global variables:

/* foo.h */
int getGlobal(void);
#define global getGlobal()

/* foo.c */
#include "foo.h"
static int actualGlobal;
void init_foo(void) {
actualGlobal = whatever;
}
int getGlobal(void) {
return actualGlobal;
}
Ah, that is a nice solution.

>
The other may be a hair more efficient, but is also a touch
less bullet-proof:
actually, I'm not sure on the efficiency part. If the library is not
dynamically loaded, wouldn't this be auto-inlined via the compiler? And if
the compiler isn't smart enough, could you add an inline anyway? That would
make this as efficient as a straight variable access. However, for dynamic
linkage, the other method would be more efficient (follow a pointer +
variable access instead of the overhead of calling a function).

Thanks,
-Jim Stapleton
Jul 15 '08 #3

P: n/a

S James S Stapleton wrote:

.... in the newsgroup *and* in E-mail; in the newsgroup *xor*
in E-mail would have been preferable.
>Eric Sosman wrote
[...]
The other may be a hair more efficient, but is also a touch
less bullet-proof:

actually, I'm not sure on the efficiency part. If the library is not
dynamically loaded, wouldn't this be auto-inlined via the compiler?
Probably not, because the module containing the "private"
global and its accessor function would be compiled separately
from the modules that used it. (If they were compiled together,
the "privacy" of the global would disappear ...) A sufficiently
smart linker might do the job, though.
And
if the compiler isn't smart enough, could you add an inline anyway? That
would make this as efficient as a straight variable access.
How would you hide the "private" global but still make it
visible to an inlined function? I suppose you could make the
"global" a local static inside the function and initialize it
on first use, but I don't know of any compilers that can actually
in-line functions with local static variables. They'd need to
somehow merge the statics from all copies of the function into
just one -- it could be done by making the static an extern and
giving it some kind of screwball name and somehow getting it to
be allocated, but ...
However, for
dynamic linkage, the other method would be more efficient (follow a
pointer + variable access instead of the overhead of calling a function).
Reasoning about efficiency is notoriously tricksy. The only
way to be sure is to measure -- and that's no walk in the park
to do meaningfully, either. Besides, measurements have a way of
turning out differently when you change compilers or flags, or
platforms, or even when you make an "unrelated" change that moves
some datum from one cache line to another ... In any case, issues
of efficiency are necessarily implementation-specific, and are not
questions about the programming language itself.

Best bets: (1) Don't worry about the efficiency of something
like this until and unless you have good reason to believe that
it's a problem, and (2) If access to these "globals" really does
turn out to be a bottleneck, make them non-globals that can live
in CPU registers instead of in main memory. (That usually means:
Make them function arguments and hope for the best.)

--
Er*********@sun.com
Jul 15 '08 #4

P: n/a
On 2008-07-15, S James S Stapleton <st**********@osu.eduwrote:
I have some code, and I want to make it future-resistant. I have a bunch of
variables that are set up run-time, and once set up, should act as
constants. I don't want to #define them, because their values are determined
during the execution of the initialization routines, so I made them const
(I'd rather making it hard for a dev to accidentally overwrite the values).
The problem is, they are being set run-time by the return of a function
call. Right now my solution is ugly, and required me to turn a .c file to a
.cpp file.
Although C++ allows for a file scope const to be initialized by the return
value of a function call, such a constant isn't a true compile-time constant.
You can't use it as a label in a switch statement, array size, etc.
Any suggestions on how to do this in a better manner?
I would just ditch const. You can save a copy of the value
in a ``secret'' variable, and at various times during the
execution of the program, assert that the two are equal.
I couldn't
find it via google or my reference books.

Basically I'm trying to make a variable non-const for one statement.

ex:
in the .h
extern const type_id CHAR_TYPE;

in the .cpp which I'd rather be a .c
const type_id CHAR_TYPE;
An uninitialized const is invalid C++!
/*...*/
void mylib_init()
{
/*note the addressing and deadressing ops, const_cast requries pointers
to work...*/
*(const_cast<type_id*>(&CHAR_TYPE)) = ctypeless_register(sizeof(char),
NULL, NULL, "char");
}
Uh, this isn't correct C++ either. You can't cast away the constness of a const
object in C++ assign to that object.

You're depending on the fact that the translation units of the program are
dealt with separately, so that the extern declared const object's value cannot
be treated as a compile-time constant.

If this ``solution'' is acceptable to you, you can do exactly the same hack in
C, except that instead of const_cast, you have to use a C cast.

The way to do this in C++ is:

// in the header
extern const type_id CHAR_TYPE;

// in the cpp
extern const type_id CHAR_TYPE = ctypeless_register(...);

C++ allows non-constant expressions to be used as the initializers of
static objects. You may run into into initialization problems. Obviously,
this code is going to be executing prior to mylib_init, and in fact
prior to main. It is arbitrarily ordered with respect to other
global initializations for other modules.

Another thing, const_cast doesn't require pointers. I suspect that can do it
with references:

const_cast<type_id &>(CHAR_TYPE) = ...

The following C++ translation unit compiles fine under gcc 3.4.3:

const int x = 3;

int main()
{
const_cast<int&>(x) = 4;
return 0;
}

But it crashes:

(gdb) r
Starting program: /home/kaz/export/a.out

Program received signal SIGSEGV, Segmentation fault.
main () at refcast.cc:5
5 const_cast<int&>(x) = 4;

The const is actually allocated in write-protected virtual memory.
(This has nothing to do with the reference cast; using pointers makes no
difference). So your const hack is not portable to this platform.
Jul 15 '08 #5

P: n/a
/* foo.h */
int getGlobal(void);
#define global getGlobal()

/* foo.c */
#include "foo.h"
static int actualGlobal;
void init_foo(void) {
actualGlobal = whatever;
}
int getGlobal(void) {
return actualGlobal;
}
I just thought of something from this, make it a non-valid lvalue without
the function overhead:

#define MY_GLOBAL (MY_HIDDEN_GLOBAL | 0)

This should have less overhead than a function, and not be 'editable',
correct? Any comments on it as opposed to the pointer method?

Thanks,
-Jim Stapleton
Jul 17 '08 #6

P: n/a
"S James S Stapleton" <st**********@osu.eduwrites:
>/* foo.h */
int getGlobal(void);
#define global getGlobal()

/* foo.c */
#include "foo.h"
static int actualGlobal;
void init_foo(void) {
actualGlobal = whatever;
}
int getGlobal(void) {
return actualGlobal;
}

I just thought of something from this, make it a non-valid lvalue without
the function overhead:

#define MY_GLOBAL (MY_HIDDEN_GLOBAL | 0)

This should have less overhead than a function, and not be 'editable',
correct? Any comments on it as opposed to the pointer method?
Writing + 0 works for more types than | 0, but even then not for all.
You can get closer with the rather odd:

#define MAKE_NAME(n) global_const_##n
#define GLOBAL(name) (1 ? MAKE_NAME(name) : MAKE_NAME(name))

since (in C) the result of ?: is not an lvalue (but not in C++).

Personally, I would just extend Eric's pointer idea to a struct:

struct constants {
int zero;
double pi;
/* ... */
};

const struct constants *constant;

and have your initialisation set the pointer once a (non-const) static
struct has been written.

--
Ben.
Jul 17 '08 #7

P: n/a
>
Writing + 0 works for more types than | 0, but even then not for all.
You can get closer with the rather odd:

#define MAKE_NAME(n) global_const_##n
#define GLOBAL(name) (1 ? MAKE_NAME(name) : MAKE_NAME(name))

since (in C) the result of ?: is not an lvalue (but not in C++).
This is only for integer values, and I plan on the code being usable in C or
C++. Actually, that's why I'm trying to keep this as pure-C as possible, I'd
like it to be trivially usable by anyone, as possible.

Even the people who've chosen to embrace D.

-Jim
Jul 17 '08 #8

P: n/a
"S James S Stapleton" <st**********@osu.eduwrites:
>>
Writing + 0 works for more types than | 0, but even then not for all.
You can get closer with the rather odd:

#define MAKE_NAME(n) global_const_##n
#define GLOBAL(name) (1 ? MAKE_NAME(name) : MAKE_NAME(name))

since (in C) the result of ?: is not an lvalue (but not in C++).

This is only for integer values, and I plan on the code being usable in C or
C++. Actually, that's why I'm trying to keep this as pure-C as possible, I'd
like it to be trivially usable by anyone, as possible.
OK. I still recommend a pointer to const struct!

--
Ben.
Jul 17 '08 #9

P: n/a
S James S Stapleton wrote:
>/* foo.h */
int getGlobal(void);
#define global getGlobal()

/* foo.c */
#include "foo.h"
static int actualGlobal;
void init_foo(void) {
actualGlobal = whatever;
}
int getGlobal(void) {
return actualGlobal;
}

I just thought of something from this, make it a non-valid lvalue without
the function overhead:

#define MY_GLOBAL (MY_HIDDEN_GLOBAL | 0)

This should have less overhead than a function, and not be 'editable',
correct? Any comments on it as opposed to the pointer method?
This is known as "security through obscurity." Note that
MY_HIDDEN_GLOBAL needs to be known by name and be accessible
everywhere MY_GLOBAL is used, so its optimistic name is just
an expression of hope.

If you can trust the programmers to leave MY_HIDDEN_GLOBAL
alone, why not just trust them not to abuse MY_GLOBAL, and be
done with all the running around? Contrariwise, if you can't
trust them to keep their hands of MY_GLOBAL, why do you suppose
they'll respect the privacy of MY_HIDDEN_GLOBAL?

It seems to me you're seeking a technical solution to what
may be a social and behavioral problem.

--
Er*********@sun.com
Jul 17 '08 #10

P: n/a
This is known as "security through obscurity." Note that
MY_HIDDEN_GLOBAL needs to be known by name and be accessible
everywhere MY_GLOBAL is used, so its optimistic name is just
an expression of hope.

If you can trust the programmers to leave MY_HIDDEN_GLOBAL
alone, why not just trust them not to abuse MY_GLOBAL, and be
done with all the running around? Contrariwise, if you can't
trust them to keep their hands of MY_GLOBAL, why do you suppose
they'll respect the privacy of MY_HIDDEN_GLOBAL?
I'm not doing this as a matter of security, more along the lines of
politeness. MY_HIDDEN_GLOBAL will have a name unlikely to be used
accidentally. MY_GLOBAL, since it's being used, might accidentally get
assigned somewhere. This is just to help with debugging issues.
It seems to me you're seeking a technical solution to what
may be a social and behavioral problem.
Sort-of. I just want to make sure that accidental errors can be more easily
traced/debugged.

-Jim Stapleton
Jul 17 '08 #11

P: n/a
* S James S Stapleton peremptorily fired off this memo:
> Two approaches I've seen used for "final" global variables:

/* foo.h */
int getGlobal(void);
#define global getGlobal()

/* foo.c */
#include "foo.h"
static int actualGlobal;
void init_foo(void) {
actualGlobal = whatever;
}
int getGlobal(void) {
return actualGlobal;
}

Ah, that is a nice solution.
Why not just:

/* foo.h */

extern int getGlobal (void);

/* foo.c */

#include "foo.h"

int
getGlobal (void)
{
static int actualGlobal = whatever;
return actualGlobal;
}
--
There are three rules for writing a novel. Unfortunately, no one knows
what they are.
-- Somerset Maugham
Jul 19 '08 #12

P: n/a
Linonut wrote:
* S James S Stapleton peremptorily fired off this memo:
>> Two approaches I've seen used for "final" global variables:

/* foo.h */
int getGlobal(void);
#define global getGlobal()

/* foo.c */
#include "foo.h"
static int actualGlobal;
void init_foo(void) {
actualGlobal = whatever;
}
int getGlobal(void) {
return actualGlobal;
}
Ah, that is a nice solution.

Why not just:

/* foo.h */

extern int getGlobal (void);
Using a #define to hide the function call is an optional
frill, possibly even an undesirable frill. As you point out,
it's not a necessary part of the solution.
/* foo.c */

#include "foo.h"

int
getGlobal (void)
{
static int actualGlobal = whatever;
return actualGlobal;
}
This assumes the `whatever' can be calculated at compile
time, but the O.P. said he wanted a value that would not be
available until run-time. (If `whatever' were in fact a
compile-time constant there'd be no need for all this running
around: You'd write `const int global = whatever;', or perhaps
even `#define global whatever'.)

It's true that you don't actually need an init_foo() if
you're willing to pay a smallish price at each access:

int getGlobal(void) {
static int initialized = 0;
static int actualGlobal;
if (! initialized) {
actualGlobal = run_time_whatever();
initialized = 1;
}
return actualGlobal;
}

.... but since the getGlobal() function itself needs only a
smallish amount of time, adding another smallish amount might
make a large percentage difference. Since the O.P. worried
about the overhead of a mere function call, I decided to show
the init_foo() step separately.

--
Eric Sosman
es*****@ieee-dot-org.invalid
Jul 19 '08 #13

P: n/a
* Eric Sosman peremptorily fired off this memo:
Linonut wrote:
>/* foo.c */

#include "foo.h"

int
getGlobal (void)
{
static int actualGlobal = whatever;
return actualGlobal;
}

This assumes the `whatever' can be calculated at compile
time, but the O.P. said he wanted a value that would not be
available until run-time.
Doh!

--
Women, deceived by men, want to marry them; it is a kind of revenge
as good as any other.
-- Philippe De Remi
Jul 25 '08 #14

This discussion thread is closed

Replies have been disabled for this discussion.