Array sizes and const

K

Keith Thompson

BartC said:
It's taking a slightly tricky concept, a 'const' attribute, and making it
even harder. Now it means read-only variables, read-only parameters, *and*
named literals.

Variables and parameters are both objects, and "const" means the same
thing for both, so it's not as tricky as you imply.
Provided it can be agreed whether a particular right-hand
expression is a constant or not; some compilers might be clever enough to
evaluate the results of certain functions, others won't. And it's still not
clear whether they are allowed as l-values or not.

The C standard defines "constant expressions" unambiguously in section
6.6. A constant expression isn't merely an expression that some
particular compiler is able to evaluate at compile time.

The C++ standard does make it perfectly clear whether such constants are
allowed as lvalues. (I haven't found the relevant wording in the C++
standard, but g++ -pedantic allows it.)
Although I suppose, compared with the rest of C++, no-one would really
notice..

Using a new keyword and a new concept would keep things simple: it would
only be used to apply a type and name to a literal. The right-hand-size
*must* be a constant (on any compiler). You can't use them as l-values. And
it would almost be the same as using the literal itself (the declaration may
introduce a cast).

Using the same mechanism that's been used in C++ for years would keep
things even simpler.

I certainly don't argue that C should adopt C++ features wholesale, but
in this case the way C++ does it is good enough, and *unnecessary*
incompatibilities are, well, unnecessary.

[...]
 
J

Joe keane

Part of the reason is that whilst int member(const FOO *obj) is clear
enough in intention, in fact the constness of obj does not extend to
its members.

know what you meant

The problem is that people often want a 'semantic' const.

For example:

struct bar
{
int bar_color;
char *bar_name;
struct whiz *bar_whiz;
};

struct const_bar
{
const int bar_color;
const char *bar_name;
const struct whiz *bar_whiz;
};

At first it looks like i made all the members 'const', but of course
that's not true.
 
T

Tim Rentsch

Les Cargill said:
I am using Mingw 3.4.5 on a 'Doze box, but it pretty much
follows any Gnu compiler I've run into.

Why is this:

---------------------------
#define SIZE 20
const int size = SIZE;
char array[SIZE];
---------------------------

legal, yet

---------------------------
#define SIZE 20
const int size = SIZE;
char array[size];
---------------------------

not?

The int size is invariant, and ... "morally"
equivalent to using SIZE, yet it won't let me do that.

And yes, I understand/speak/grok preprocessor vs.
compiler. I know *how*, I just wonder *why*. Is
this a practical, strategic or tactical thing,
or am I just being silly? Was it a conscious decision
of the committee, or just one of those things?

I would like to offer some contrasting opinions to those of
Ian Collins (and no disrepect intended, I just have some
different views to suggest).

At the time C was first standardized, I don't think any C
implementations had this capability. (I was working
actively in C++ during this time, and I don't remember C++
having it either.) Whether it was considered or not, the
committee chose to be cautiously conservative and not
include such a rule in the Standard, and IMO that was an
apppropriate policy at that time.

Subsequently, I suspect it wasn't added for some combination
of (a) no one proposing/championing it, (b) little or no
experience with C implementations that offer it, and / or
(c) no perception of any significant demand.

Personally I would tend to side with those in category (c).
As language features go this one doesn't offer very much.
I know a lot of people don't like the C preprocessor, but
except for that I don't see any significant benefit from
providing this capability. Why complicate the language
definition needlessly?

Incidentally, note that the Standard actually does allow
implementations to accept the example code without
complaint, under paragraph 10 of the section on Constant
Expressions. (Some other people who post in c.l.c don't
agree with this conclusion; note however that gcc's
behavior, to give one example, agrees with my assessment.)
Despite having the freedom to accept this construct, I'm not
aware of any implementations (of C) that do. That probably
means there haven't been a lot of people clamoring for it.
 
L

Les Cargill

Tim said:
Les Cargill said:
I am using Mingw 3.4.5 on a 'Doze box, but it pretty much
follows any Gnu compiler I've run into.

Why is this:

---------------------------
#define SIZE 20
const int size = SIZE;
char array[SIZE];
---------------------------

legal, yet

---------------------------
#define SIZE 20
const int size = SIZE;
char array[size];
---------------------------

not?

The int size is invariant, and ... "morally"
equivalent to using SIZE, yet it won't let me do that.

And yes, I understand/speak/grok preprocessor vs.
compiler. I know *how*, I just wonder *why*. Is
this a practical, strategic or tactical thing,
or am I just being silly? Was it a conscious decision
of the committee, or just one of those things?

I would like to offer some contrasting opinions to those of
Ian Collins (and no disrepect intended, I just have some
different views to suggest).

At the time C was first standardized, I don't think any C
implementations had this capability. (I was working
actively in C++ during this time, and I don't remember C++
having it either.) Whether it was considered or not, the
committee chose to be cautiously conservative and not
include such a rule in the Standard, and IMO that was an
apppropriate policy at that time.

Subsequently, I suspect it wasn't added for some combination
of (a) no one proposing/championing it, (b) little or no
experience with C implementations that offer it, and / or
(c) no perception of any significant demand.

Personally I would tend to side with those in category (c).
As language features go this one doesn't offer very much.

It really doesn't offer much. The only reason I asked is
because there's been a gradual movement away from K&R to
..... something else.
I know a lot of people don't like the C preprocessor,

I am not one of them. In lots of cases, I *prefer* it.
Attempts to eliminate the preprocessor are generally
somewhat/somehow worse than what they replace.
but
except for that I don't see any significant benefit from
providing this capability. Why complicate the language
definition needlessly?

The only "why" is that you now have two thingies - one's
a macro, one's a const object, and they have slightly
different semantics, despite me wanting them to be the same
thing :)

It's by no means a huge problem.
 
T

Tim Rentsch

Les Cargill said:
Tim said:
Les Cargill said:
I am using Mingw 3.4.5 on a 'Doze box, but it pretty much
follows any Gnu compiler I've run into.

Why is this:

---------------------------
#define SIZE 20
const int size = SIZE;
char array[SIZE];
---------------------------

legal, yet

---------------------------
#define SIZE 20
const int size = SIZE;
char array[size];
---------------------------

not?

[snip]
... I don't see any significant benefit from
providing this capability. Why complicate the language
definition needlessly?

The only "why" is that you now have two thingies - one's
a macro, one's a const object, and they have slightly
different semantics, despite me wanting them to be the same
thing :) [snip]

I suggest that there are at least a couple of other
reasons. First is that the new method would need
to be documented in the Standard. Readers of the
Standard know that many aspects that are seemingly
simple take an inordinate amount of description
(and discussion about what the description should
be) to specify. In other words there is work
involved to do it, and the committee has plenty of
other, more important, things to keep them busy.

Second is that if such a capability were put in,
it's only a matter of time before someone wants
a "natural" extension to handle other possible
cases. For example, what about this:

const int size;
char array[size];

...

const int size = 20;

This should be easy to implement; why not have it
(or so the argument would go)?

For another example, what about this:

extern const int size;
char array[size];

... and in another translation unit

const int size = 20;

This also shouldn't be too hard to implement. It
needs more elaborate linker technology, but given
what all else relocating linker/loaders do, that
isn't too much of a stretch.

I'm not trying to say that such arguments would be
convincing; only that suggestions like these would
be made (and arguments to go with them). Once the
door is opened, it's almost for sure that some
people will want to open it farther. Better not
to open the door in the first place.
 
J

Joe keane

Even after all these years, I *really* want it to mean that...

Pascal

(but it had this insane thing of requiring you to put them in a certain
order, and it didn't have header files so it is moot)
 
K

Keith Thompson

Tim Rentsch said:
Les Cargill said:
I am using Mingw 3.4.5 on a 'Doze box, but it pretty much
follows any Gnu compiler I've run into.

Why is this:
[snip]

Incidentally, note that the Standard actually does allow
implementations to accept the example code without
complaint, under paragraph 10 of the section on Constant
Expressions. (Some other people who post in c.l.c don't
agree with this conclusion; note however that gcc's
behavior, to give one example, agrees with my assessment.)
Despite having the freedom to accept this construct, I'm not
aware of any implementations (of C) that do. That probably
means there haven't been a lot of people clamoring for it.

How does gcc's behavior agree with your assessment?

$ cat c.c
const int max = 42;
int arr[max];
$ gcc -c c.c
c.c:2:5: error: variably modified ‘arr’ at file scope
$ gcc -std=c99 -pedantic -c c.c
c.c:2:5: error: variably modified ‘arr’ at file scope
$
 
L

Les Cargill

Tim said:
Les Cargill said:
Tim said:
I am using Mingw 3.4.5 on a 'Doze box, but it pretty much
follows any Gnu compiler I've run into.

Why is this:

---------------------------
#define SIZE 20
const int size = SIZE;
char array[SIZE];
---------------------------

legal, yet

---------------------------
#define SIZE 20
const int size = SIZE;
char array[size];
---------------------------

not?

[snip]
... I don't see any significant benefit from
providing this capability. Why complicate the language
definition needlessly?

The only "why" is that you now have two thingies - one's
a macro, one's a const object, and they have slightly
different semantics, despite me wanting them to be the same
thing :) [snip]

I suggest that there are at least a couple of other
reasons. First is that the new method would need
to be documented in the Standard. Readers of the
Standard know that many aspects that are seemingly
simple take an inordinate amount of description
(and discussion about what the description should
be) to specify. In other words there is work
involved to do it, and the committee has plenty of
other, more important, things to keep them busy.

Second is that if such a capability were put in,
it's only a matter of time before someone wants
a "natural" extension to handle other possible
cases. For example, what about this:

const int size;
char array[size];

...

const int size = 20;

This should be easy to implement; why not have it
(or so the argument would go)?

For another example, what about this:

extern const int size;
char array[size];

... and in another translation unit

const int size = 20;

This also shouldn't be too hard to implement. It
needs more elaborate linker technology, but given
what all else relocating linker/loaders do, that
isn't too much of a stretch.

I'm not trying to say that such arguments would be
convincing; only that suggestions like these would
be made (and arguments to go with them). Once the
door is opened, it's almost for sure that some
people will want to open it farther. Better not
to open the door in the first place.


That is actually not a bad argument at all, and probably
close to the truth.
 
T

Tim Rentsch

Keith Thompson said:
Tim Rentsch said:
Les Cargill said:
I am using Mingw 3.4.5 on a 'Doze box, but it pretty much
follows any Gnu compiler I've run into.

Why is this:
[snip]

Incidentally, note that the Standard actually does allow
implementations to accept the example code without
complaint, under paragraph 10 of the section on Constant
Expressions. (Some other people who post in c.l.c don't
agree with this conclusion; note however that gcc's
behavior, to give one example, agrees with my assessment.)
Despite having the freedom to accept this construct, I'm not
aware of any implementations (of C) that do. That probably
means there haven't been a lot of people clamoring for it.

How does gcc's behavior agree with your assessment?

$ cat c.c
const int max = 42;
int arr[max];
$ gcc -c c.c
c.c:2:5: error: variably modified 'arr' at file scope
$ gcc -std=c99 -pedantic -c c.c
c.c:2:5: error: variably modified 'arr' at file scope
$

Gcc accepts some expressions as integer constant expressions that
don't satisfy the criteria in 6.6 p6. It doesn't accept this
particular example, but it does for some others. For example,
after including <stdlib.h>, a macro call

offsetof( struct { int x; int y; }, y )

expands (in my local gcc) to

((size_t) &((struct { int x; int y; } *)0)->y)

which clearly doesn't satisfy the conditions of 6.6 p6, and yet
the declaration

int x[ offsetof( struct { int x; int y; }, y ) ];

is accepted (as a top-level declaration) without complaint.
(The use of offsetof() here doesn't affect the behavior - a
similar declaration using the expansion shown above works
just as well in an array declaration.)

Corollory to the above observations, gcc accepts the premise
that 6.6p10 gives permission to accept other expressions
as integer constant expressions, even though they do not
satisfy 6.6 p6. The example using a declared variable
as the dimension of an array declarator could, if an
implementation so chose, fall into that category.
 
J

Joe keane

Agreed - and that's probably the most important thing I'm "missing"
here.

CPP is a bit... inelegant

but so far as

#define BAR_INIT_NUM_STICKS 10

even

#define BAR_IS_RED(BAR) (((BAR)->bar_fl & 0x70) == 0x10)

i never had a problem with it
 

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
474,079
Messages
2,570,574
Members
47,207
Latest member
HelenaCani

Latest Threads

Top