Explanation needed for const int "error: variably modified ... atfile scope."

P

Poster Matt

Hi,

The following code results in the following error with GCC (v.4.3.2):

const int eodSize = 8192;
char eodContents[eodSize];

error: variably modified 'eodContents' at file scope


It is, of course, easily solved by ditching the 'const int' and using a #define
instead like this:

#define eodSize 8192
char eodContents[eodSize];

I would understand the error if "const int eodSize = 8192;" was not a constant
but since it is a constant why does the compiler not allow it?

Thanks.
 
B

bart.c

Poster Matt said:
Hi,

The following code results in the following error with GCC (v.4.3.2):

const int eodSize = 8192;
char eodContents[eodSize];

error: variably modified 'eodContents' at file scope


It is, of course, easily solved by ditching the 'const int' and using a
#define instead like this:

#define eodSize 8192
char eodContents[eodSize];

I would understand the error if "const int eodSize = 8192;" was not a
constant but since it is a constant why does the compiler not allow it?

const doesn't mean what you think.

Just use:

enum {eodSize=8192};

as #define has it's own problems.
 
B

Ben Pfaff

Poster Matt said:
The following code results in the following error with GCC (v.4.3.2):

const int eodSize = 8192;
char eodContents[eodSize];

This is in the FAQ:

11.8: I don't understand why I can't use const values in initializers
and array dimensions, as in

const int n = 5;
int a[n];

A: The const qualifier really means "read-only"; an object so
qualified is a run-time object which cannot (normally) be
assigned to. The value of a const-qualified object is therefore
*not* a constant expression in the full sense of the term. (C
is unlike C++ in this regard.) When you need a true compile-
time constant, use a preprocessor #define (or perhaps an enum).

References: ISO Sec. 6.4; H&S Secs. 7.11.2,7.11.3 pp. 226-7.
 
K

Keith Thompson

Poster Matt said:
The following code results in the following error with GCC (v.4.3.2):

const int eodSize = 8192;
char eodContents[eodSize];

error: variably modified 'eodContents' at file scope


It is, of course, easily solved by ditching the 'const int' and using
a #define instead like this:

#define eodSize 8192
char eodContents[eodSize];

I would understand the error if "const int eodSize = 8192;" was not a
constant but since it is a constant why does the compiler not allow
it?

Because "const" doesn't mean "constant"; it really means "read-only".

The language *could* have stated that a const object with an
initializer that's a constant expression is a constant <OT>as C++
does</OT>, but it doesn't.

Note that this is legal (at block scope):

const int r = rand();

r obviously isn't constant (in the sense of being evaluable at compile
time), but it is "const", i.e., read-only, in the sense that you're
not allowed to modify it:

r = 42; /* constraint violation */

.... at least not directly:

*(int*)&r = 42; /* undefined behavior, not a constraint violation */

bart.c points out the enum trick, which I find preferable to using
a macro:

enum { eodSize = 8192 };

One drawback is that enumeration constants can only be of type int.
 
P

Poster Matt

bart.c said:
Poster Matt said:
Hi,

The following code results in the following error with GCC (v.4.3.2):

const int eodSize = 8192;
char eodContents[eodSize];

error: variably modified 'eodContents' at file scope


It is, of course, easily solved by ditching the 'const int' and using
a #define instead like this:

#define eodSize 8192
char eodContents[eodSize];

I would understand the error if "const int eodSize = 8192;" was not a
constant but since it is a constant why does the compiler not allow it?

const doesn't mean what you think.

Just use:

enum {eodSize=8192};

as #define has it's own problems.

const means exactly what I think. It specifies that the value of the variable
will not be changed.

What on earth is wrong with using #define as I have used it above? It seems to
me to be perfectly fine. Note: "#define eodSize 8192" is not being defined
inside a function.

But I was looking for an explanation...

Cheers.
 
P

Poster Matt

Ben said:
Poster Matt said:
The following code results in the following error with GCC (v.4.3.2):

const int eodSize = 8192;
char eodContents[eodSize];

This is in the FAQ:

11.8: I don't understand why I can't use const values in initializers
and array dimensions, as in

const int n = 5;
int a[n];

A: The const qualifier really means "read-only"; an object so
qualified is a run-time object which cannot (normally) be
assigned to. The value of a const-qualified object is therefore
*not* a constant expression in the full sense of the term. (C
is unlike C++ in this regard.) When you need a true compile-
time constant, use a preprocessor #define (or perhaps an enum).

References: ISO Sec. 6.4; H&S Secs. 7.11.2,7.11.3 pp. 226-7.

Oops, sorry. Thanks for the info.
 
P

Poster Matt

Poster said:
bart.c said:
Poster Matt said:
Hi,

The following code results in the following error with GCC (v.4.3.2):

const int eodSize = 8192;
char eodContents[eodSize];

error: variably modified 'eodContents' at file scope


It is, of course, easily solved by ditching the 'const int' and using
a #define instead like this:

#define eodSize 8192
char eodContents[eodSize];

I would understand the error if "const int eodSize = 8192;" was not a
constant but since it is a constant why does the compiler not allow it?

const doesn't mean what you think.

Just use:

enum {eodSize=8192};

as #define has it's own problems.

const means exactly what I think. It specifies that the value of the
variable will not be changed.

Ok I was a bit quick with my reply - it doesn't mean exactly what I thought it
meant. <Head held in shame smiley>

K&R is a bit unclear about it to say the least - see my reply to Keith.

Cheers.
 
B

bart.c

Poster Matt said:
bart.c wrote:
const int eodSize = 8192;
char eodContents[eodSize];

error: variably modified 'eodContents' at file scope
It is, of course, easily solved by ditching the 'const int' and using a
#define instead like this:

#define eodSize 8192
char eodContents[eodSize];

I would understand the error if "const int eodSize = 8192;" was not a
constant but since it is a constant why does the compiler not allow it?

const doesn't mean what you think.

Just use:

enum {eodSize=8192};

as #define has it's own problems.

const means exactly what I think. It specifies that the value of the
variable will not be changed.

Most people who ask that assume that 'const' defines an actual constant (not
a memory location containing a value). Your wording ("...but since it is a
constant ...") suggested you thought the same.
What on earth is wrong with using #define as I have used it above? It
seems to me to be perfectly fine. Note: "#define eodSize 8192" is not
being defined inside a function.

Yes, #define names have too wide a visibility for many cases; enum doesn't
have that problem and comes closest to what some people expect 'const' to
do, at least for int values. But you seem to know all the answers already..
But I was looking for an explanation...

I expected someone else to provide that; I just gave an alternative
workaround..
 
P

Poster Matt

Keith said:
Poster Matt said:
The following code results in the following error with GCC (v.4.3.2):

const int eodSize = 8192;
char eodContents[eodSize];

error: variably modified 'eodContents' at file scope


It is, of course, easily solved by ditching the 'const int' and using
a #define instead like this:

#define eodSize 8192
char eodContents[eodSize];

I would understand the error if "const int eodSize = 8192;" was not a
constant but since it is a constant why does the compiler not allow
it?

Because "const" doesn't mean "constant"; it really means "read-only".

The language *could* have stated that a const object with an
initializer that's a constant expression is a constant <OT>as C++
does</OT>, but it doesn't.

K&R is somewhat misleading then when it says:

"The qualifier const can be applied to any variable to specify that its value
will not be changed."
Note that this is legal (at block scope):

const int r = rand();

r obviously isn't constant (in the sense of being evaluable at compile
time), but it is "const", i.e., read-only, in the sense that you're
not allowed to modify it:

r = 42; /* constraint violation */

Ok got it.

... at least not directly:

*(int*)&r = 42; /* undefined behavior, not a constraint violation */

bart.c points out the enum trick, which I find preferable to using
a macro:

enum { eodSize = 8192 };

One drawback is that enumeration constants can only be of type int.

Why is it in any way preferable to use this 'enum trick' to a #define?

Thanks Keith.
 
S

Seebs

I would understand the error if "const int eodSize = 8192;" was not a constant
but since it is a constant why does the compiler not allow it?

It is not a constant.

An object you can't write to is not a constant. You still have to look up
the value at runtime (since nothing prevents some other aspect of the system
from modifying the "constant" value).

-s
 
K

Keith Thompson

Poster Matt said:
K&R is somewhat misleading then when it says:

"The qualifier const can be applied to any variable to specify that
its value will not be changed."

How is that unclear? As far as I can tell, it's perfectly accurate;
const specifies that the value of the variable (I would have said
"object") will not be changed. It doesn't specify that it's a
"constant" (where "constant" means roughly that its value can be
evaluated at compile time).

For example:
[...]

How could the statement in K&R be made clearer?
Why is it in any way preferable to use this 'enum trick' to a #define?

Thanks Keith.

The preprocessor is basically a language grafted on top of
another language, with radically different syntax and semantics.
A macro definition is not scoped; it remains visible from the
point of declaration to the end of the translation unit. In more
complex cases, you have to add extra parentheses and/or use the
"do ... while(0)" trick to avoid subtle conflicts between the macro
expansion and the language syntax.

For a simple case like

#define eodSize 8192

it's not too bad; you're probably not going to have anything
else with that name, so the scoping issue doesn't really matter.
(But note that the convention is for macro names to be all-caps:
EOD_SIZE -- but identifiers starting with E and either a digit
or another uppercase letter are reserved as error macro names
in <errno.h>.)

Macros, like any other language feature, are fine if you know what
you're doing, but they're particularly easy to misuse if you're
not careful. I personally prefer to use other language features
when possible.
 
P

Poster Matt

Keith said:
How is that unclear? As far as I can tell, it's perfectly accurate;
const specifies that the value of the variable (I would have said
"object") will not be changed. It doesn't specify that it's a
"constant" (where "constant" means roughly that its value can be
evaluated at compile time).

I'm not sure I should have said 'misleading', but it certainly does not tell the
whole story. To my mind the quotation above implies that the value specified in
the source code will not be changed. So I'd never have thought "const int r =
rand();" was allowed.

The preprocessor is basically a language grafted on top of
another language, with radically different syntax and semantics.
A macro definition is not scoped; it remains visible from the
point of declaration to the end of the translation unit. In more
complex cases, you have to add extra parentheses and/or use the
"do ... while(0)" trick to avoid subtle conflicts between the macro
expansion and the language syntax.

For a simple case like

#define eodSize 8192

it's not too bad; you're probably not going to have anything
else with that name, so the scoping issue doesn't really matter.
(But note that the convention is for macro names to be all-caps:
EOD_SIZE -- but identifiers starting with E and either a digit
or another uppercase letter are reserved as error macro names
in <errno.h>.)

Macros, like any other language feature, are fine if you know what
you're doing, but they're particularly easy to misuse if you're
not careful. I personally prefer to use other language features
when possible.

Ok, many thanks for the detailed explanation, it's appreciated. I still have a
lot to learn, funny that cos I thought I was getting pretty good. :)

Re: Macro variable name - the name in my actual code was quite long and
descriptive, so I made up a fake name for posting here. eodSize and eodContents
were named simply because I had a DVD rental on my desk of a Mel Gibson movie
called Edge of Darkness, when the thought entered my mind to make a more concise
name for posting, the DVD was in my field of view, hence 'eod'. I didn't
capitalize the #define version out of laziness when copying'n'pasting.

Thanks again. I've learnt another new thing about C today. I'll get there
eventually...(I hope).

Cheers.
 
B

Ben Bacarisse

Poster Matt said:
I'm not sure I should have said 'misleading', but it certainly does
not tell the whole story. To my mind the quotation above implies that
the value specified in the source code will not be changed.

More than implies -- it says so explicitly and unambiguously!
So I'd
never have thought "const int r = rand();" was allowed.

There's really no contradiction. To take an example:

for (int i = 1; i <= 10; i++) {
const int r = rand();
printf("%d\n", r * r / i);
}

the value of "the" const object never changes (in fact any attempt to do
so is either a constraint violation or will produce undefined
behaviour).

I put "the" in quotes because it is the use of phrases like "the const
object r" that leads to confusion. The way to think of this is that a
new object called r appears in every iteration and is destroyed at the
end of the loop body (in each iteration). There are, one after the
other, 10 const objects called r and the value in each and every one
never changes during its lifetime.

People naturally get sloppy and talk about "the object r", but then it
seems as if r can change but it doesn't -- not during the lifetime of
the object.

<snip>
 
T

Tim Streater

Poster Matt said:
Re: Macro variable name - the name in my actual code was quite long and
descriptive, so I made up a fake name for posting here. eodSize and
eodContents
were named simply because I had a DVD rental on my desk of a Mel Gibson movie
called Edge of Darkness, when the thought entered my mind to make a more
concise
name for posting, the DVD was in my field of view, hence 'eod'. I didn't
capitalize the #define version out of laziness when copying'n'pasting.

Ha! You are Keyser Söze and I claim my £5.
 
P

Peter Nilsson

Keith Thompson said:
How is that unclear?

Well the preface to K&R says...

The book is not an introductory programming manual; it
assumes some familiarity with basic programming concepts...

Most people's familiarity of variables whose 'values will not
be changed,' and especially a CONST keyword, is that of true
constants, not the weaker 'don't write' ones that C employs.
As far as I can tell, it's perfectly accurate; const
specifies that the value of the variable (I would have
said "object") will not be changed. It doesn't specify
that it's a "constant" (where "constant" means roughly
that its value can be evaluated at compile time).

Yes, it clearly doesn't say that const is a constant. But
it would have been better if it cleary added that const
_isn't_ a constant.
 
P

Poster Matt

Ben said:
More than implies -- it says so explicitly and unambiguously!

Not quite, K&R says the "value will not be changed", I said the "value specified
in the source code will not be changed", in other words I mean a fixed constant
value EG. 3.1415, "Keyser Söze", etc., and not some kind of dynamic assignment
like the const int r = rand() example.

There's really no contradiction. To take an example:

for (int i = 1; i <= 10; i++) {
const int r = rand();
printf("%d\n", r * r / i);
}

the value of "the" const object never changes (in fact any attempt to do
so is either a constraint violation or will produce undefined
behaviour).

I put "the" in quotes because it is the use of phrases like "the const
object r" that leads to confusion. The way to think of this is that a
new object called r appears in every iteration and is destroyed at the
end of the loop body (in each iteration). There are, one after the
other, 10 const objects called r and the value in each and every one
never changes during its lifetime.

People naturally get sloppy and talk about "the object r", but then it
seems as if r can change but it doesn't -- not during the lifetime of
the object.

Ok, got it. :)

Cheers.
 
P

Poster Matt

Keith said:
Ok, I see what you mean.

What it really means is that the value will not be changed *once
the object has been initialized*. Once you understand that, it's a
bit difficult to interpret in any other way. (That's why I asked;
the better I understand how beginners can misunderstand things that
seem obvious to me, the better I can explain them.)

That's how I could have answered your earlier question of "How could the
statement in K&R be made clearer?".

K&R amendment (given my lowly level this seems rather arrogant to even attempt,
let alone publicly):

Original: "The qualifier const can be applied to any variable to specify that
its value will not be changed."

Amended: "The qualifier const can be applied to any variable to specify that its
value will not be changed after it has been initialized."


Trust me Keith - you're there. :)

Cheers.
 
P

Poster Matt

Peter said:
Well the preface to K&R says...

The book is not an introductory programming manual; it
assumes some familiarity with basic programming concepts...

Most people's familiarity of variables whose 'values will not
be changed,' and especially a CONST keyword, is that of true
constants, not the weaker 'don't write' ones that C employs.


Yes, it clearly doesn't say that const is a constant. But
it would have been better if it cleary added that const
_isn't_ a constant.

Peter I couldn't have put it clearer myself. In fact I didn't put it clearer.

Thanks for making my point better than I made it. :)

Cheers.
 
B

Ben Bacarisse

Poster Matt said:
That's how I could have answered your earlier question of "How could
the statement in K&R be made clearer?".

K&R amendment (given my lowly level this seems rather arrogant to even
attempt, let alone publicly):

Original: "The qualifier const can be applied to any variable to
specify that its value will not be changed."

Amended: "The qualifier const can be applied to any variable to
specify that its value will not be changed after it has been
initialized."

This is one of those cases where you risk confusing others who have a
different picture. Some people have the (incorrect) view that a
variable is initialised when it first gets assigned a value. I.e. they
would take your wording as permitting

const int x;
x = 42;

Of course that is not what you intended to suggest, but then K&R did not
intend their words to suggest what you originally took from them!

Finally, your version is unclear in one very technical way. What does
it say about a const variable that is not initialised at all? Automatic
const variables that are defined without an initialiser are not even
implicitly initialised, so presumably their values *can* be changed or
maybe the phrase says nothing at all about such variables?

Simplifying things for the purposes of getting the main ideas across is
an important technique, but I get the feeling that K&R prefer to be as
minimal and as technically accurate as possible. I like that style (I
am always searching for the "K&R of XYZ" when leaning a new language)
but they do run the risk of people reading more into what is written
than is supported by the text or, for that matter, of finding it too
dense.
 

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

No members online now.

Forum statistics

Threads
473,731
Messages
2,569,432
Members
44,832
Latest member
GlennSmall

Latest Threads

Top