Fog Creek Software
Discussion Board




Call me a tinkerer

const int x = 100;

...actually stores a doubleword in memory (I checked).

Isn't it (a little) overkill to actually allocate memory for a constant -- instead of just substituting it at compile time? All right, that's the only way for strings, but integers?

Yes, the word I'm looking for is #define, but Stroustrup suggests const instead.

Alex
Tuesday, November 25, 2003

In C and C++, consts can be modified by casting away the const.

Mike
Tuesday, November 25, 2003

But an int on a 32 bit machine is 32 bits so when you say const int = 100; you are really saying const int = 0x00000064;. If you don't want 32 bits, you need to choose a smaller type.

dmooney
Tuesday, November 25, 2003

The compiler may optimise it out of existence (effectively substituting the value at compile time). If it doesn't and if when you are profiling you discover that this is the main cause of your program being inefficient then you can make some form of localised change to optimise the situation.

Len Holgate (www.lenholgate.com)
Tuesday, November 25, 2003

How, exactly, did you check?

Mr Jack
Tuesday, November 25, 2003

It's same as var int x=100;
You may write const x=100;  // to avoid allocation

AV
Tuesday, November 25, 2003

Nothing stops you from taking a pointer to x in another file.

For this reason, the compiler will allocate memory for it.

Also, you technically need to declare the static in code somewhere, to tell the compiler where to allocate the memory.

NotSoCool GCC mis-feature:

const int foo = 3;
const int bar = 7;

z = q ? foo : bar;

The object code for this expression will actually reference the value in memory, so if you don't allocate it somewhere you will get a link error.  This is kosher according to the C++ spec, so it is not a bug.

David Jones
Tuesday, November 25, 2003

>> How, exactly, did you check?

I took a pointer to it, incremented-decremented it, and it took out the correct value.

>> z = q ? foo : bar;

I agree. Also it needs to be in memory in case anyone might want a pointer to it. I'm sure it's not a bug of course.

Alex
Tuesday, November 25, 2003

>> You may write const x=100;  // to avoid allocation

Nice! I didn't know that! (ashamed)

Alex
Tuesday, November 25, 2003

"I took a pointer to it, incremented-decremented it, and it took out the correct value."

Exactly, You Took A Pointer To It. C++ will only treat it as a symbolic substitution if you _don't_ do this.

Mr Jack
Tuesday, November 25, 2003

If you just say

    const int x = 100;

then (in C, but not in C++) x has external linkage and *must* be explicitly present in case another compilation unit's code refers to x or even to &x. But if you say

    static const int x = 100;

or (in C++)

    namespace { const int x = 100; }

then there is no need for actual memory to be used, and with a good compiler it should not be. (Except perhaps if you ask for no optimization and lots of debuggability.)

Even when x is really present in memory, a good compiler should be able to generate code that doesn't actually refer to that memory (again, within the same compilation unit, where the value of x is known).

Consider the following code:

    const int x = 100; // (1)
    static const int x = 100; // (2)
    namespace { const int x = 100; } // (3)
    int f() { return x; } // (all versions)

With GCC version 2.95.3 on my box:
  - all three versions allocate space for x by default
  - all three versions produce code for f that doesn't need a memory reference to load the constant value 100
  - with -O (a minimal level of optimization), versions 2 and 3 avoid allocating space for x
  - compiling with g++, version 1 also avoids allocating space when -O is specified
  - compiling with gcc, version 1 allocates space even with -O3 (maximum optimization, more or less)

The fact that you can cast away constness is nothing to do with this. Doing so is in general an error and the standard permits your programs to break if you do that.

I'm not sure what David Jones means about a GCC misfeature. For me, (1) the generated code doesn't use foo and bar as such, but loads the constants directly; (2) the definitions of the constants' values are present in the same object file, so I'm not sure how you'd get them not to be present anyway. I expect I'm misunderstanding him...

Gareth McCaughan
Tuesday, November 25, 2003

Hate to be pedantic, but casting away constness is only undefined if the variable being referred to was originally declared as const. I don't think it's fair to say that it's "in general an error". C++ even explicitly supports it with const_cast.

Adrian Gilby
Tuesday, November 25, 2003

Gareth, not so. Constants have file scope in C++.

Mr Jack
Tuesday, November 25, 2003

Doh! you already said that. Shouldn't skim read. Sorry.

Mr Jack
Tuesday, November 25, 2003

(Parts of the following might have been obliquely said earlier.)

In module A:

const int x = 100;

In module B:

extern const int x;

The external constant might be defined in one module (file) and used in another. Later, the module containing the definition might be recompiled with a different value.

You want the uncompiled modules to use the new values. Therefore, the compiler will not substitute the literal value. This is because the compiler can't determine that another module might reference the value.

The "const" statement is a request to the compiler to allocate memory (and stuff a value into it).

The only cases where it would be safe for a compiler to consider substituting the value is when the scope of the constant is restricted to a module (i.e. the "static' keyword is used) or the constant is an automatic.

njkayaker
Tuesday, November 25, 2003

const x=100
and
const int x=100

Are exactly the same statements! If your compiler says otherwise, it's not following the standard.

int is implied whenever not explicitly stated. for example:

unsigned y;
is a shortcut for
unsigned int y;

A standard encompassing compiler will compile the following statement:

f;

...which is valid C.

Dennis Atkins, Language Lawyer
Tuesday, November 25, 2003

const need not necessarily allocate memory for the variable.

If you specify your constant should have external linkage, space for it will be generated. It has to be, so the other files that reference it can find it.

If you don't specify external linkage -- the default unless you say "extern" ("static const" is a tautology) -- memory should be allocated for it only if you take it saddress or use it as an lvalue. But even then, the compiler is free to substitute the constant itself any time it's used as an rvalue.

Example:

; 4    : const int x=100;

CONST    SEGMENT
_x    DD    100
CONST    ENDS


; 5    : void b_f() {

<snip>

; 6    :     printf("b_f: x=%d\n",x);

  00003    push     100
  00005    push     OFFSET FLAT:$SG599
  0000a    call     _printf
  0000f    add     esp, 8

; 7    :     ++const_cast<int &>(x);

  00012    mov     eax, DWORD PTR _x
  00017    add     eax, 1
  0001a    mov     DWORD PTR _x, eax

; 8    :     printf("b_f: x=%d\n",x);

  0001f    push     100
  00021    push     OFFSET FLAT:$SG601
  00026    call     _printf
  0002b    add     esp, 8

; 9    : }

<snip>

Remove the ++ bit (or, on this compiler, compile an optimised build) and the memory allocated for x magically disappears.

Note: if you're talking C, that's a bit different. I'm not sure how (I never used const when I was into C.), but I believe "const" means read only rather than necessarily constant. This implies that const doesn't imply static, which implies the compiler is obliged to generate the constant in memory, and that the generated code must refer to it as if it were non-const.

Insert half smiley here.
Tuesday, November 25, 2003

static const is a tautology?

In what way?

static int x = 100; /* local scope, can be modified */
const int x = 100; /* global scope,can't portably be modified */
static const int x = 100; /* local scope, can't portably be modified */

static vs. extern controls visibility
const vs. non const controls storage and access

Ori Berger
Tuesday, November 25, 2003


NOTE THAT there appear to be differences between C and C++. (I'm talking about C.)

Within a function, "static" causes the compiler to create variable in "external" memory (which persists through out the "life time" of the running program. Without it (typical), the variable is an automatic (i.e. created on the stack).

Outside of functions, in C, everything is external by default. The "static" keyword indicates that the external object can only be referenced in the module that defines it.

In C, the "extern" keyword signifies that the statement is a declaration not a definition (a definition, ala K&R, is a statement that creates the memory). One can use "extern" in function prototypes, but it's unnecessary because the compiler can tell a function prototype from a function definition. In C, the "extern" keyword is not a "visibilty" thing (it only looks like it is).

Thus, in C.

Module A:

const int c = 100;

void FuncA() {};

Module B:

extern int c; // "extern" says c is defined somewhere else (resolve at link time) and treat it like an integer.

void FuncB() {};

Module C:

// The following will happily compile AND link. The consequences, though, could be VERY ugly!

extern double c; // "extern" says c is defined somewhere else (resolve at link time) and treat it like an double.

void FuncC() {};

njkayaker
Tuesday, November 25, 2003

You know you've been coding in perl too long when you look at other language code and feel uncomfortable because the variable foo doesn't have a $ infront of it.

$foo = 1

Jack of all
Tuesday, November 25, 2003

One reason nobody seems to have touched on is that for some targets, the variables you declare const are located in ROM...  If you tried to do a compile time substitution it might work out OK with a single numerical value, but what if you had const structs?  Wouldn't it make sense that they would be allocated somewhere?

radius
Wednesday, November 26, 2003

>> Remove the ++ bit (or, on this compiler, compile an optimised build) and the memory allocated for x magically disappears.

Yes, and it will compile, only it won't run because the const variables are in read-only memory :)

>>  00012    mov    eax, DWORD PTR _x
>>  00017    add    eax, 1
>>  0001a    mov    DWORD PTR _x, eax

But will it ever replace the above monstrosity with

inc DWORD PTR _x

?

Alex
Wednesday, November 26, 2003

enum {x = 100};

I can't remember if this is internally changed to a const or what.


Wednesday, November 26, 2003

The asm comes from a debug build. (VC++.NET) Debug builds seem to treat every variable as if it were volatile. You'd probably get a plain inc in an optimised build, but what happened was the code for it disappeared entirely since it has no effect on the rest of the code. That's that whole "undefined" thing!

As for "static const", it is a tautology in C++, but clearly not in C. My mistake.

const in C++ works a bit like enum, but as well as creating a compile-time constant it (maybe) allocates memory for it so you can take its address and so on. That's how you can have const float and const struct, whereas enum is limited to integers.

Insert half smiley here.
Wednesday, November 26, 2003

Adrian Gilby -- sorry, I wasn't clear enough. I'd say: in general, it is not legal to cast away constness. You are allowed to do it in the special case where the thing you're unconstifying was originally declared non-const. I guess you'd say: in general, it is legal, but you're not allowed to do it when the thing you're unconstifying was originally declared as const. :-)

Gareth McCaughan
Thursday, November 27, 2003

*  Recent Topics

*  Fog Creek Home