Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Array sizes and const

79 views
Skip to first unread message

Les Cargill

unread,
Jun 2, 2012, 4:43:40 PM6/2/12
to

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?

Thanks in a advance for any consideration.

--
Les Cargill

Ian Collins

unread,
Jun 2, 2012, 4:56:30 PM6/2/12
to
On 06/ 3/12 08:43 AM, Les Cargill wrote:
>
> 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?

Because const is broken in C.

> 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?

My guess would be an oversight in the original standard. It's
unfortunate that two opportunities to correct it have now been missed.

--
Ian Collins

Eric Sosman

unread,
Jun 2, 2012, 4:59:10 PM6/2/12
to
`const' doesn't mean "constant." Roughly speaking, it means
"unwritable" -- and even that's not quite true, because a
`const volatile' object might be writable by something outside C
itself (a hardware timer, for example, might be read-only to the
C program but writeable by a little silicon doodad).

With that in mind, back to your question. In `char array[SIZE];'
the macro is replaced by the token `20', and that token represents
an integer literal, something that is in fact constant. But in
`char array[size];', `size' is a variable that will acquire some
value when the program is eventually executed. In this case it is
easy to see what the (initial) value will be, but nonetheless: It's
a variable, not a constant.

Just for added fun (or confusion), the "C99" version of the C
Standard added a rule to the language that allows for a "variable-
length array" whose dimension is computed at run-time rather than
at compile time. Taken as a VLA, `char array[size];' is perfectly
legal: It's an array with `size' elements (whatever `size' happens
to be at the moment), and which gets memory allocated to it when the
declaration is reached. However, file-scope arrays (and `static'
arrays inside functions) get their memory before the program even
starts, so their dimensions must be known prior to execution. A
VLA must have `auto' storage, meaning that it can only exist inside
a function.

--
Eric Sosman
eso...@ieee-dot-org.invalid

Les Cargill

unread,
Jun 2, 2012, 5:35:42 PM6/2/12
to
Agreed - and that's probably the most important thing I'm
"missing" here. Ah, the const keyword...

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

> Roughly speaking, it means
> "unwritable" -- and even that's not quite true, because a
> `const volatile' object might be writable by something outside C
> itself (a hardware timer, for example, might be read-only to the
> C program but writeable by a little silicon doodad).
>

Sure. "Not writable by this program". And when I must mix const and
volatile, I still end up reading about it...

What we usually want is a const pointer to a volatile object. But
not always - for things like... DMA controllers ( in kernel mode )
we may express pointers in hardware registers... so it may be
a const pointer to a volatile *pointer*.

I did a quick Google, and it seems to be a serious point of confusion.
A thing to translate all the permutations of const/static/volatile
to English would be very handy...

The examples seem to avoid pointer syntax, which is unfortunate.

> With that in mind, back to your question. In `char array[SIZE];'
> the macro is replaced by the token `20', and that token represents
> an integer literal, something that is in fact constant.

Yessir.

> But in
> `char array[size];', `size' is a variable that will acquire some
> value when the program is eventually executed. In this case it is
> easy to see what the (initial) value will be, but nonetheless: It's
> a variable, not a constant.
>

And a declaration cannot depend on a variable, whether it is
invariant or not...

> Just for added fun (or confusion), the "C99" version of the C
> Standard added a rule to the language that allows for a "variable-
> length array" whose dimension is computed at run-time rather than
> at compile time. Taken as a VLA, `char array[size];' is perfectly
> legal: It's an array with `size' elements (whatever `size' happens
> to be at the moment), and which gets memory allocated to it when the
> declaration is reached. However, file-scope arrays (and `static'
> arrays inside functions) get their memory before the program even
> starts, so their dimensions must be known prior to execution. A
> VLA must have `auto' storage, meaning that it can only exist inside
> a function.
>


--
Les Cargill

Les Cargill

unread,
Jun 2, 2012, 5:43:18 PM6/2/12
to
<snip>

Here's a terrible example:

http://icecube.wisc.edu/~dglo/c_class/const_vol.html

int
check_iobuf(void)
{
volatile int iobuf;
int val;

while (iobuf == 0) {
}
val = iobuf;
iobuf = 0;
return(val);
}

Unless I miss my guess, "iobuf" is an *auto*. It's
not mapped as a hardware register, no external
asynchronous process can change it.... it's on
the local stack...

I suppose you can have it be "extern volatile int iobuf" and
use the linker to put it in a hardware-interesting "segment"
but imagine the confusion promulgated by that bad example. it's
even apparently an infinite loop...

One compiler for 68000 used an "@" operator to
declare something as "int Thing = @0x50000;" for
this... I don't have an example and am working from memory.


--
Les Cargill

Keith Thompson

unread,
Jun 2, 2012, 5:59:49 PM6/2/12
to
Les Cargill <lcarg...@comcast.com> writes:
> 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?

Both are legal if they occur inside a function definition, where the
second is a variable-length array (VLA) declaration.

At file scope, VLAs are not allowed.

Given:

const int size = 20;

"size" is still considered an ordinary object; a reference to it is
*not* a constant expression. Any compiler worth its salt will convert a
reference to that object to a literal 20 (assuming that results in
faster code), but that's an optimization; in the abstract machine it
fetches the value of the object (which will always be 20).

The key thing to remember is that the "const" keyword doesn't mean
"constant". A "constant" expression is one that can be (and in many
cases must be) evaluated at compile time. The "const" keyword really
means read-only. For example, the following is a perfectly legal
declaration (inside a function):

const int r = rand();

(Note that C++ has slightly different rules; in C++, a reference to
"size" *is* a constant expression.)

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Les Cargill

unread,
Jun 2, 2012, 6:12:49 PM6/2/12
to
Keith Thompson wrote:
> Les Cargill<lcarg...@comcast.com> writes:
>> 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?
>
> Both are legal if they occur inside a function definition, where the
> second is a variable-length array (VLA) declaration.
>

I have not been able to find the -c99 switch for MingW 3.4.5.... don't
think it does it...

> At file scope, VLAs are not allowed.
>
> Given:
>
> const int size = 20;
>
> "size" is still considered an ordinary object; a reference to it is
> *not* a constant expression. Any compiler worth its salt will convert a
> reference to that object to a literal 20 (assuming that results in
> faster code), but that's an optimization; in the abstract machine it
> fetches the value of the object (which will always be 20).
>

Well, there you go. "const" isn't really const... it's a 'C' term of
art....

> The key thing to remember is that the "const" keyword doesn't mean
> "constant". A "constant" expression is one that can be (and in many
> cases must be) evaluated at compile time. The "const" keyword really
> means read-only. For example, the following is a perfectly legal
> declaration (inside a function):
>
> const int r = rand();
>
> (Note that C++ has slightly different rules; in C++, a reference to
> "size" *is* a constant expression.)
>

Right! We are in an infinity of twisty mazes :)

--
Les Cargill

Nobody

unread,
Jun 2, 2012, 6:50:03 PM6/2/12
to
On Sat, 02 Jun 2012 15:43:40 -0500, Les Cargill wrote:

> 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?

K&R C didn't have "const". Along with "volatile", it was added during the
standardisation process to facilitate optimisation.

The main purpose of "const" is to tell the compiler to assume that the
value won't change. However, a const-qualified variable is still an
lvalue, not a compile-time constant; changing that was presumably
considered too radical.

If you want a compile-time integer constant, you can use enum, e.g.:

enum { size = SIZE };

This "trick" is still quite common in C++ code due to some compilers being
a bit late to accept that a "static const" member really is a compile-time
constant in C++, and the preprocessor not being an acceptable substitute
when the name has to belong to a class or namespace.

Ian Collins

unread,
Jun 2, 2012, 6:53:24 PM6/2/12
to
Only in code written in the last century!

--
Ian Collins

James Kuyper

unread,
Jun 2, 2012, 9:11:15 PM6/2/12
to
On 06/02/2012 06:50 PM, Nobody wrote:
...
> The main purpose of "const" is to tell the compiler to assume that the
> value won't change.

I don't think that's the main purpose. In my opinion, the most important
thing about 'const', and the reason why I use it where appropriate, is
that it turns many dangerous constructs into constraint violations,
making a diagnostic mandatory.
--
James Kuyper

Keith Thompson

unread,
Jun 2, 2012, 9:27:46 PM6/2/12
to
Les Cargill <lcarg...@comcast.com> writes:
> Keith Thompson wrote:
[...]
> I have not been able to find the -c99 switch for MingW 3.4.5.... don't
> think it does it...

Try "-std=c99".

>> At file scope, VLAs are not allowed.
>>
>> Given:
>>
>> const int size = 20;
>>
>> "size" is still considered an ordinary object; a reference to it is
>> *not* a constant expression. Any compiler worth its salt will convert a
>> reference to that object to a literal 20 (assuming that results in
>> faster code), but that's an optimization; in the abstract machine it
>> fetches the value of the object (which will always be 20).
>>
>
> Well, there you go. "const" isn't really const... it's a 'C' term of
> art....

"const" is a C keyword. Unlike "constant", it's not an English word
with a pre-existing meaning. It means exactly what the language says it
means.

"const" does mean "const". It just doesn't mean "constant".

>> The key thing to remember is that the "const" keyword doesn't mean
>> "constant". A "constant" expression is one that can be (and in many
>> cases must be) evaluated at compile time. The "const" keyword really
>> means read-only. For example, the following is a perfectly legal
>> declaration (inside a function):
>>
>> const int r = rand();
>>
>> (Note that C++ has slightly different rules; in C++, a reference to
>> "size" *is* a constant expression.)
>>
>
> Right! We are in an infinity of twisty mazes :)

And even in C++, given:

const int r = rand();

a reference to r is not a constant expression. (It can't be; there's no
way to evaluate it at compile time.)

BTW, there is a limited workaround. If you want size to be a constant
expression, without using the preprocessor, you can write:

enum { size = 20 };

Enumeration constants are of type int, and references to them are
constant expressions. You can't use this to create constants of types
other than int, though.

Les Cargill

unread,
Jun 2, 2012, 11:27:07 PM6/2/12
to
I like the enum trick - hadn't seen that before.

--
Les Cargill

BartC

unread,
Jun 3, 2012, 6:24:27 AM6/3/12
to
"Les Cargill" <lcarg...@comcast.com> wrote in message
news:jqe303$id9$1...@dont-email.me...
> Keith Thompson wrote:

>> (Note that C++ has slightly different rules; in C++, a reference to
>> "size" *is* a constant expression.)
>>
>
> Right! We are in an infinity of twisty mazes :)

I've never got the hang of 'const' in C.

Using it like this:

const int a = 1000;

means a gets the value 1000, then can't be changed. OK.

Now you try this:

int b=2000;
const int* p = &b;

means, I think, that you can't change b via the the pointer. But you *can*
change p to point somewhere else. To protect p itself, it's necessary to
write:

int* const p = &b;

Now you can write: *p=3000; but you can't write p=&c. (I've just looked this
up online which is how I know...)

To keep p readonly, and not allow it's target to be changed either,
presumably you have to write:

const int * const p = &b;

Perfectly clear :-)

But, who care's about that; what I want to know is why, at some point during
the last forty years, didn't someone just add a feature like:

constant int d = 4000;

and it means exactly that: d is a synonym for the literal d. It has a
precise type, and follows normal scoping rules. You also can't use it as an
lvalue so it is guaranteed to have that value. It can also be used to
initialise fixed size arrays, and does not to be written in capitals.

It's a five-minute job to add to the language (exaggerating a little, but it
is pretty trivial to implement). Instead we have a series of unsatisfactory
alternatives: #define, const (which doesn't work, or works but you
unintentionally end up with a VLA), and enum{}, which you described as a
'trick'...

--
Bartc

Nobody

unread,
Jun 3, 2012, 9:35:37 AM6/3/12
to
On Sun, 03 Jun 2012 10:53:24 +1200, Ian Collins wrote:

>> If you want a compile-time integer constant, you can use enum, e.g.:
>>
>> enum { size = SIZE };
>>
>> This "trick" is still quite common in C++ code due to some compilers being
>> a bit late to accept that a "static const" member really is a compile-time
>> constant in C++, and the preprocessor not being an acceptable substitute
>> when the name has to belong to a class or namespace.
>
> Only in code written in the last century!

Or code intended to work with compilers written in the last century.

For large code bases, it's not uncommon to just keep using the compiler
for which the very first lines of code were written, which then requires
keeping all subsequent code compatible with that compiler.

Although I don't think you'd actually have to go back 12 years to find a
compiler that didn't handle "static const" correctly.

Malcolm McLean

unread,
Jun 3, 2012, 10:39:05 AM6/3/12
to
בתאריך יום ראשון, 3 ביוני 2012 02:11:15 UTC+1, מאת James Kuyper:
I never use it. 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. Another is the const-poisoning problem. You have to use const consistently, or you end up needing to pass a const pointer to a non-const subroutine which doesn't in fact alter the data.
Then C++ added mutable. This makes a member of a const class non-const. The fact that mutable was considered necessary is an argument against const.

But the main reason is simply visual clutter. You want to be able to see what a function does at a glance.


James Kuyper

unread,
Jun 3, 2012, 4:03:02 PM6/3/12
to
On 06/03/2012 10:39 AM, Malcolm McLean wrote:
...
> does not extend to its members. Another is the const-poisoning
> problem. You have to use const consistently, or you end up needing to
> pass a const pointer to a non-const subroutine which doesn't in fact
> alter the data.

I don't see that as a problem. Forcing consistent use of const is good
mental discipline; the casts that are needed to interface with libraries
that don't use it correctly helps document those library's faults.
--
James Kuyper

David Brown

unread,
Jun 3, 2012, 4:46:58 PM6/3/12
to
In C, although you still can't declare a file-scope array of size "size"
with "static const size = 100;", it is still better to make your "const"
values "static" if you can. Even though the compiler can't break the
language rules and make "char array[size];" legal, it can at least do
better optimisation with the static const.

Ben Bacarisse

unread,
Jun 3, 2012, 4:49:19 PM6/3/12
to
Malcolm McLean <malcolm...@btinternet.com> writes:

> בתאריך יום ראשון, 3 ביוני 2012 02:11:15 UTC+1, מאת James Kuyper:
>> On 06/02/2012 06:50 PM, Nobody wrote:
>> ...
>> > The main purpose of "const" is to tell the compiler to assume that the
>> > value won't change.
>>
>> I don't think that's the main purpose. In my opinion, the most important
>> thing about 'const', and the reason why I use it where appropriate, is
>> that it turns many dangerous constructs into constraint violations,
>> making a diagnostic mandatory.
>>
> I never use it. 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.

Can you say what you mean by this? It contradicts what I thought was
the case (assuming you meant the members of *obj).

<snip>
--
Ben.

Keith Thompson

unread,
Jun 3, 2012, 4:51:08 PM6/3/12
to
"BartC" <b...@freeuk.com> writes:
[...]
> But, who care's about that; what I want to know is why, at some point
> during the last forty years, didn't someone just add a feature like:
>
> constant int d = 4000;
>
> and it means exactly that: d is a synonym for the literal d. It has a
> precise type, and follows normal scoping rules. You also can't use it
> as an lvalue so it is guaranteed to have that value. It can also be
> used to initialise fixed size arrays, and does not to be written in
> capitals.
>
> It's a five-minute job to add to the language (exaggerating a little,
> but it is pretty trivial to implement). Instead we have a series of
> unsatisfactory alternatives: #define, const (which doesn't work, or
> works but you unintentionally end up with a VLA), and enum{}, which
> you described as a 'trick'...

In fact someone did do that: Bjarne Stroustrup, when he was designing
C++.

Except that he didn't introduce a new keyword; he just tweaked the
semantics of "const".

In C++, if you declare

const some_type x = init_expr;

x becomes a constant expression *if* some_type is arithmetic *and*
init_expr is a constant expression. Otherwise, it has pretty much the
same meaning it has in C. (I probably haven't gotten that 100% right,
but that's the general idea.)

So, for example, in C++ (which doesn't have VLAs) you can have this:

{
const int array_size = 20;
int arr[arr_size];
}

but not this:

{
const int array_size = rand() % 20 + 1;
int arr[arr_size]; // invalid
}

I don't think it would have been terribly difficult for C to adopt this
feature, and I think it would have been a good idea. Maybe for C202x.

Ian Collins

unread,
Jun 3, 2012, 5:08:01 PM6/3/12
to
On 06/ 4/12 02:39 AM, Malcolm McLean wrote:
> בתאריך יום ראשון, 3 ביוני 2012 02:11:15 UTC+1, מאת James Kuyper:
>> On 06/02/2012 06:50 PM, Nobody wrote:
>> ...
>>> The main purpose of "const" is to tell the compiler to assume that the
>>> value won't change.
>>
>> I don't think that's the main purpose. In my opinion, the most important
>> thing about 'const', and the reason why I use it where appropriate, is
>> that it turns many dangerous constructs into constraint violations,
>> making a diagnostic mandatory.

Please please wrap your lines!

> I never use it. 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.

Eh? What if FOO is in read only memory?

> Another is the const-poisoning problem. You have to use const consistently,
> or you end up needing to pass a const pointer to a non-const subroutine
> which doesn't in fact alter the data.

So good coding discipline is bad?

> Then C++ added mutable. This makes a member of a const class non-const.
> The fact that mutable was considered necessary is an argument against
const.

Mutable is rarely used in C++. Most of the cases in my own code are for
internal state variables.

> But the main reason is simply visual clutter. You want to be able to see
> what a function does at a glance.

Isn't whether the function modifies its arguments one of the most
important things you want to see at a glance?

--
Ian Collins

Keith Thompson

unread,
Jun 3, 2012, 5:49:33 PM6/3/12
to
Agreed.

typedef struct foo {
int x;
} FOO;

int member(const FOO *obj) {
obj->x = 42;
return 43;
}

int main(void) {
FOO foo_obj;
int m = member(&foo_obj);
return 0;
}

c.c: In function ‘member’:
c.c:6:5: error: assignment of member ‘x’ in read-only object

Malcolm McLean

unread,
Jun 3, 2012, 6:02:14 PM6/3/12
to
בתאריך יום ראשון, 3 ביוני 2012 21:49:19 UTC+1, מאת Ben Bacarisse:
> Malcolm McLean <malcolm...@btinternet.com> writes:
>
> > I never use it. 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.
>
> Can you say what you mean by this? It contradicts what I thought was
> the case (assuming you meant the members of *obj).
>
typedef struct
{
char *name;
} EMPLOYEE;

const char *getname(const EMPLOYEE *employee)
{
strcpy(employee->name, "Fred");
return employee->name;
}

Malcolm McLean

unread,
Jun 3, 2012, 6:08:19 PM6/3/12
to
בתאריך יום ראשון, 3 ביוני 2012 22:08:01 UTC+1, מאת Ian Collins:
> On 06/ 4/12 02:39 AM, Malcolm McLean wrote:
>
> Isn't whether the function modifies its arguments one of the most
> important things you want to see at a glance?
>
Usually it's obvious

double mean(double *x, int N)

isn't going to modify x.

What you might argue is that

double median(double *x, int N)

could reasonably sort x as a side-effect. Make it const, and you've documented that this isn't the case. I'd say this is sufficiently rare to make const non-useful as a documenting feature.

Ian Collins

unread,
Jun 3, 2012, 6:37:58 PM6/3/12
to
On 06/ 4/12 10:08 AM, Malcolm McLean wrote:
> בתאריך יום ראשון, 3 ביוני 2012 22:08:01 UTC+1, מאת Ian Collins:
>> On 06/ 4/12 02:39 AM, Malcolm McLean wrote:
>>
>> Isn't whether the function modifies its arguments one of the most
>> important things you want to see at a glance?
>>
> Usually it's obvious
>
> double mean(double *x, int N)
>
> isn't going to modify x.
>
> What you might argue is that
>
> double median(double *x, int N)

Pretty please wrap your lines!

> could reasonably sort x as a side-effect. Make it const, and you've
> documented that this isn't the case. I'd say this is sufficiently
> rare to make const non-useful as a documenting feature.

But what isn't rare is something like

const double dd[] = { 1.0, 2.0, 3.1 };

mean(dd);

Which will trigger an appropriate diagnostic.

If a function doesn't modify a parameter, declare it const. What's so
hard about that?

--
Ian Collins

BartC

unread,
Jun 3, 2012, 6:47:25 PM6/3/12
to
"Ian Collins" <ian-...@hotmail.com> wrote in message
news:a327a6...@mid.individual.net...
Because nineteen times out of twenty, it won't modify it, so it means loads
of const attributes cluttering up code.

Of course some parameter types can be harmlessly modified (ints for
example), and const isn't necessary, but then you have to start thinking
about about every parameter and whether it will be modified in the caller or
in the callee.

Maybe it would have been better for the modifiable parameters (where it
changes caller's data) to have an attribute instead, and everything else
assumed to be const.

--
Bartc

Ian Collins

unread,
Jun 3, 2012, 6:55:33 PM6/3/12
to
On 06/ 4/12 10:47 AM, BartC wrote:
> "Ian Collins"<ian-...@hotmail.com> wrote in message
> news:a327a6...@mid.individual.net...
>> On 06/ 4/12 10:08 AM, Malcolm McLean wrote:
>
>>> could reasonably sort x as a side-effect. Make it const, and you've
>>> documented that this isn't the case. I'd say this is sufficiently
>>> rare to make const non-useful as a documenting feature.
>>
>> But what isn't rare is something like
>>
>> const double dd[] = { 1.0, 2.0, 3.1 };
>>
>> mean(dd);
>>
>> Which will trigger an appropriate diagnostic.
>>
>> If a function doesn't modify a parameter, declare it const. What's so
>> hard about that?
>
> Because nineteen times out of twenty, it won't modify it, so it means loads
> of const attributes cluttering up code.
>
> Of course some parameter types can be harmlessly modified (ints for
> example), and const isn't necessary, but then you have to start thinking
> about about every parameter and whether it will be modified in the caller or
> in the callee.

Isn't that part of the design process? Naturally it's pointless
declaring a value type parameter const, but pointer types should be.
Not doing so in the past has given us the glorious mess of a language
permitting a string literal to be passed to function with a char* parameter.

--
Ian Collins

Malcolm McLean

unread,
Jun 3, 2012, 7:04:53 PM6/3/12
to
בתאריך יום ראשון, 3 ביוני 2012 23:55:33 UTC+1, מאת Ian Collins:
>
> Isn't that part of the design process? Naturally it's pointless
> declaring a value type parameter const, but pointer types should be.
> Not doing so in the past has given us the glorious mess of a language
> permitting a string literal to be passed to function with a char* parameter.
>
One very common paradigm is the opaque pointer.
We might have a threedengine structure, and a member function for drawing
triangles. If we draw a triangle, the engine might add it to a draw list,
or it might pass it to the rendering hardware directly. It's none of caller's
business how it does it.
But if it sends the triangle to the rendering hardware directly, the ENGINE *
is a const. If it buffers it, it is mutable.


Ian Collins

unread,
Jun 3, 2012, 7:14:38 PM6/3/12
to
There's a good example of the confusion, does it modify the triangle or
not? From the description you give, it looks like if does not in either
case.

It is very much the callers business to know whether the triangle it
passes will or will not be molested by the function. What if it has a
table of triangles in read only memory?

The constness of the parameter has nothing to do with how the function
does its job.

--
Ian Collins

BartC

unread,
Jun 3, 2012, 7:23:16 PM6/3/12
to
"Ian Collins" <ian-...@hotmail.com> wrote in message
news:a329ev...@mid.individual.net...
> On 06/ 4/12 11:04 AM, Malcolm McLean wrote:
>> בתאריך יום ראשון, 3 ביוני 2012 23:55:33 UTC+1, מאת Ian Collins:

>> But if it sends the triangle to the rendering hardware directly, the
>> ENGINE *
>> is a const. If it buffers it, it is mutable.
>
> There's a good example of the confusion, does it modify the triangle or
> not? From the description you give, it looks like if does not in either
> case.
>
> It is very much the callers business to know whether the triangle it
> passes will or will not be molested by the function. What if it has a
> table of triangles in read only memory?
>
> The constness of the parameter has nothing to do with how the function
> does its job.

Would a const attribute be any use here:

#include <stdio.h>
#include <string.h>

void changestr(char* s){
s[0]='?';
}

int main(void)
{
changestr("abcdef");
puts("abcdef");
}

I want to able to use changestr() to modify a string variable. But how can I
stop a string literal being passed (which will either corrupt the literal,
or will crash, on my tests)?

It's possible the new write-attribute I mentioned a couple of posts ago (eg.
'var' to mean the opposite of 'const') could be useful here. Then the
compiler knows passing the string literal is a mistake.

(And I can't find a gcc warning level to tell me that a string literal is
being passed as a non-const char* parameter which could potentially
overwrite it.)

--
Bartc

Ian Collins

unread,
Jun 3, 2012, 7:30:50 PM6/3/12
to
On 06/ 4/12 11:23 AM, BartC wrote:
> "Ian Collins"<ian-...@hotmail.com> wrote in message
> news:a329ev...@mid.individual.net...
>> On 06/ 4/12 11:04 AM, Malcolm McLean wrote:
>>> בתאריך יום ראשון, 3 ביוני 2012 23:55:33 UTC+1, מאת Ian Collins:
>
>>> But if it sends the triangle to the rendering hardware directly, the
>>> ENGINE *
>>> is a const. If it buffers it, it is mutable.
>>
>> There's a good example of the confusion, does it modify the triangle or
>> not? From the description you give, it looks like if does not in either
>> case.
>>
>> It is very much the callers business to know whether the triangle it
>> passes will or will not be molested by the function. What if it has a
>> table of triangles in read only memory?
>>
>> The constness of the parameter has nothing to do with how the function
>> does its job.
>
> Would a const attribute be any use here:

Yes, change it and see:

void changestr(const char* s)

gcc x.c
x.c: In function ‘changestr’:
x.c:5:3: error: assignment of read-only location ‘*s’

> #include<stdio.h>
> #include<string.h>
>
> void changestr(char* s){
> s[0]='?';
> }
>
> int main(void)
> {
> changestr("abcdef");
> puts("abcdef");
> }
>
> I want to able to use changestr() to modify a string variable. But how can I
> stop a string literal being passed (which will either corrupt the literal,
> or will crash, on my tests)?

That's the "glorious mess" I mentioned up-thread.

C++ fixed this one, but I'm sure if the C committee tries, the fossils
would pop up and whine about breaking existing (already broken) code.

--
Ian Collins

BartC

unread,
Jun 3, 2012, 7:52:58 PM6/3/12
to


"Ian Collins" <ian-...@hotmail.com> wrote in message
news:a32ada...@mid.individual.net...
> On 06/ 4/12 11:23 AM, BartC wrote:

>> Would a const attribute be any use here:
>
> Yes, change it and see:
>
> void changestr(const char* s)
>
> gcc x.c
> x.c: In function ‘changestr’:
> x.c:5:3: error: assignment of read-only location ‘*s’

But then I can't use changestr() for it's intended purpose!

> That's the "glorious mess" I mentioned up-thread.
>
> C++ fixed this one, but I'm sure if the C committee tries, the fossils
> would pop up and whine about breaking existing (already broken) code.

In the meantime, coding seems simpler without bothering with 'const' all.

--
Bartc

Ian Collins

unread,
Jun 3, 2012, 8:04:47 PM6/3/12
to
On 06/ 4/12 11:52 AM, BartC wrote:
>
>
> "Ian Collins"<ian-...@hotmail.com> wrote in message
> news:a32ada...@mid.individual.net...
>> On 06/ 4/12 11:23 AM, BartC wrote:
>
>>> Would a const attribute be any use here:
>>
>> Yes, change it and see:
>>
>> void changestr(const char* s)
>>
>> gcc x.c
>> x.c: In function ‘changestr’:
>> x.c:5:3: error: assignment of read-only location ‘*s’
>
> But then I can't use changestr() for it's intended purpose!

Ah, I see your point. The rest of my reply still applies!

>> That's the "glorious mess" I mentioned up-thread.
>>
>> C++ fixed this one, but I'm sure if the C committee tries, the fossils
>> would pop up and whine about breaking existing (already broken) code.
>
> In the meantime, coding seems simpler without bothering with 'const' all.

Or find a compiler option that does the check. -Wwrite-strings does the
trick for gcc.

--
Ian Collins

Ben Bacarisse

unread,
Jun 3, 2012, 8:21:48 PM6/3/12
to
What's that got to do with what you said? The object being modified by
strcpy is not a member of *employee.

--
Ben.

Ben Bacarisse

unread,
Jun 3, 2012, 8:33:33 PM6/3/12
to
Ian Collins <ian-...@hotmail.com> writes:

> On 06/ 4/12 10:47 AM, BartC wrote:
>> "Ian Collins"<ian-...@hotmail.com> wrote in message
<snip>
>>> If a function doesn't modify a parameter, declare it const. What's so
>>> hard about that?
>>
>> Because nineteen times out of twenty, it won't modify it, so it means loads
>> of const attributes cluttering up code.
>>
>> Of course some parameter types can be harmlessly modified (ints for
>> example), and const isn't necessary, but then you have to start thinking
>> about about every parameter and whether it will be modified in the caller or
>> in the callee.
>
> Isn't that part of the design process? Naturally it's pointless
> declaring a value type parameter const, but pointer types should
> be.

A minor point...

You keep talking about declaring parameters const when a function does
not modify them (and now BartC has taken you at your word) but you are
not, I think, talking about const parameters, nor about pointer
parameters being const, (as above), but about parameters that are
pointers to const types.

I know that "a const pointer" is a commonly used phrase, but it can be
really confusing because it's literally not what is usually meant.

<snip>
--
Ben.

Ian Collins

unread,
Jun 3, 2012, 8:35:56 PM6/3/12
to
On 06/ 4/12 12:33 PM, Ben Bacarisse wrote:
> Ian Collins<ian-...@hotmail.com> writes:
>
>> On 06/ 4/12 10:47 AM, BartC wrote:
>>> "Ian Collins"<ian-...@hotmail.com> wrote in message
> <snip>
>>>> If a function doesn't modify a parameter, declare it const. What's so
>>>> hard about that?
>>>
>>> Because nineteen times out of twenty, it won't modify it, so it means loads
>>> of const attributes cluttering up code.
>>>
>>> Of course some parameter types can be harmlessly modified (ints for
>>> example), and const isn't necessary, but then you have to start thinking
>>> about about every parameter and whether it will be modified in the caller or
>>> in the callee.
>>
>> Isn't that part of the design process? Naturally it's pointless
>> declaring a value type parameter const, but pointer types should
>> be.
>
> A minor point...
>
> You keep talking about declaring parameters const when a function does
> not modify them (and now BartC has taken you at your word) but you are
> not, I think, talking about const parameters, nor about pointer
> parameters being const, (as above), but about parameters that are
> pointers to const types.

I am, thank you for the clarification.

--
Ian Collins

Ben Bacarisse

unread,
Jun 3, 2012, 8:39:54 PM6/3/12
to
"BartC" <b...@freeuk.com> writes:
<snip>
> Would a const attribute be any use here:
>
> #include <stdio.h>
> #include <string.h>
>
> void changestr(char* s){
> s[0]='?';
> }
>
> int main(void)
> {
> changestr("abcdef");
> puts("abcdef");
> }
>
> I want to able to use changestr() to modify a string variable. But how
> can I stop a string literal being passed (which will either corrupt
> the literal, or will crash, on my tests)?
>
> It's possible the new write-attribute I mentioned a couple of posts
> ago (eg. 'var' to mean the opposite of 'const') could be useful
> here. Then the compiler knows passing the string literal is a mistake.
>
> (And I can't find a gcc warning level to tell me that a string literal
> is being passed as a non-const char* parameter which could potentially
> overwrite it.)

"gcc -Wwrite-strings" makes string literals const (and thus the
resulting pointer becomes a const char *). This is how C++ treats
strings.

It has the curious side effect of making gcc non-conforming even with
all the right other options (-std=c99 -pedantic). The reason is far too
obscure to worry about in practice. I find it a very useful option.

--
Ben.

Malcolm McLean

unread,
Jun 4, 2012, 5:35:35 AM6/4/12
to
בתאריך יום שני, 4 ביוני 2012 00:14:38 UTC+1, מאת Ian Collins:
I didn't tell you how the triangle was passed, whether as a structure, buffer,
or set of separate parameters.
Generally you know whether the triangle will be molested or not. If the engine
needs some temporay state, then the triangle structure will have members with
names like "reserved_flag" and so on. What's much more likely is that the
engine doesn't buffer the triangle vertices independently. It just keeps a
pointer to them. If you over-write the vertices before you call the frame
synch, you'll get the wrong triangle. But const won't help you with that.

With the ENGINE parameter, you don't know whether drawing a triangle affects
the state or not, nor should you. And that's a common paradigm. const breaks
the paradigm here.


BartC

unread,
Jun 4, 2012, 7:20:54 AM6/4/12
to
"Keith Thompson" <ks...@mib.org> wrote in message
news:lny5o4d...@nuthaus.mib.org...
> "BartC" <b...@freeuk.com> writes:

>> why ... didn't someone just add a feature like:
>>
>> constant int d = 4000;

> In fact someone did do that: Bjarne Stroustrup, when he was designing
> C++.
>
> Except that he didn't introduce a new keyword; he just tweaked the
> semantics of "const".
>
> In C++, if you declare
>
> const some_type x = init_expr;
>
> x becomes a constant expression *if* some_type is arithmetic *and*
> init_expr is a constant expression. Otherwise, it has pretty much the
> same meaning it has in C. (I probably haven't gotten that 100% right,
> but that's the general idea.)

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. 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.

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).

However it would only make sense for primitives: values that could
correspond to 'immediate' data in machine code, and which don't need any
storage reserved. A named string literal doesn't work as well (as it would
still need storage).

--
Bartc

Jens Gustedt

unread,
Jun 4, 2012, 7:54:18 AM6/4/12
to
Am 04.06.2012 13:20, schrieb BartC:
> "Keith Thompson" <ks...@mib.org> wrote in message
> news:lny5o4d...@nuthaus.mib.org...
>> "BartC" <b...@freeuk.com> writes:
>
>>> why ... didn't someone just add a feature like:
>>>
>>> constant int d = 4000;
>
>> In fact someone did do that: Bjarne Stroustrup, when he was designing
>> C++.
>>
>> Except that he didn't introduce a new keyword; he just tweaked the
>> semantics of "const".
>>
>> In C++, if you declare
>>
>> const some_type x = init_expr;
>>
>> x becomes a constant expression *if* some_type is arithmetic *and*
>> init_expr is a constant expression. Otherwise, it has pretty much the
>> same meaning it has in C. (I probably haven't gotten that 100% right,
>> but that's the general idea.)
>
> 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. 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.

agreed

> 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).

No I don't think that a new keyword would be needed. Alowing const
qualified register "variables" in file scope would do the trick.

register struct toto const A = { .x = 42 };

would give you real literals for almost any data type. For such
variables no aliasing is possible (no one can take their adress) and so
they can be considered as real constants.

They could easily be declared-defined in any header file since they
wouldn't need to generate an external symbol.

Jens





James Kuyper

unread,
Jun 4, 2012, 12:08:43 PM6/4/12
to
On 06/03/2012 10:39 AM, Malcolm McLean wrote:
...
> ... 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.

A compiler for which that was the case would be non-conforming. It
violates 6.5.2.3p4: "A postfix expression followed by the -> operator
and an identifier designates a member of a structure or union object.
... If the first expression is a pointer to a qualified type, the result
has the so-qualified version of the type of the designated member." Can
you provide an example of a compiler claiming to conform to the C
standard which treats a member of *obj as though it was not const-qualified?

Alan Curry

unread,
Jun 4, 2012, 5:28:14 PM6/4/12
to
In article <jqgpig$plu$1...@dont-email.me>, BartC <b...@freeuk.com> wrote:
>"Ian Collins" <ian-...@hotmail.com> wrote in message
>news:a327a6...@mid.individual.net...
>>
>> If a function doesn't modify a parameter, declare it const. What's so
>> hard about that?
>
>Because nineteen times out of twenty, it won't modify it, so it means loads
>of const attributes cluttering up code.

The omission of const qualifiers clutters the code with spurious requests for
write access.

const-as-default for pointer target types is a good idea. It would be nice to
have it in the language, but the next best thing is to have it in your coding
style.

--
Alan Curry

Keith Thompson

unread,
Jun 4, 2012, 5:32:06 PM6/4/12
to
"BartC" <b...@freeuk.com> writes:
> "Keith Thompson" <ks...@mib.org> wrote in message
> news:lny5o4d...@nuthaus.mib.org...
>> "BartC" <b...@freeuk.com> writes:
>
>>> why ... didn't someone just add a feature like:
>>>
>>> constant int d = 4000;
>
>> In fact someone did do that: Bjarne Stroustrup, when he was designing
>> C++.
>>
>> Except that he didn't introduce a new keyword; he just tweaked the
>> semantics of "const".
>>
>> In C++, if you declare
>>
>> const some_type x = init_expr;
>>
>> x becomes a constant expression *if* some_type is arithmetic *and*
>> init_expr is a constant expression. Otherwise, it has pretty much the
>> same meaning it has in C. (I probably haven't gotten that 100% right,
>> but that's the general idea.)
>
> 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.

[...]

Joe keane

unread,
Jun 4, 2012, 6:49:41 PM6/4/12
to
In article <39346056-1528-4667...@googlegroups.com>,
Malcolm McLean <malcolm...@btinternet.com> wrote:
>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.

Tim Rentsch

unread,
Jun 8, 2012, 5:08:53 AM6/8/12
to
Les Cargill <lcarg...@comcast.com> writes:

> 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.

Les Cargill

unread,
Jun 8, 2012, 7:45:52 AM6/8/12
to
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.

> 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.
>

--
Les Cargill

Tim Rentsch

unread,
Jun 8, 2012, 1:49:13 PM6/8/12
to
Les Cargill <lcarg...@comcast.com> writes:

> Tim Rentsch wrote:
>> Les Cargill <lcarg...@comcast.com> writes:
>>
>>> 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.

Joe keane

unread,
Jun 8, 2012, 4:05:15 PM6/8/12
to
In article <jqe0qg$758$1...@dont-email.me>,
Les Cargill <lcarg...@comcast.com> wrote:
>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)

Keith Thompson

unread,
Jun 8, 2012, 4:31:34 PM6/8/12
to
Tim Rentsch <t...@alumni.caltech.edu> writes:
> Les Cargill <lcarg...@comcast.com> writes:
>> 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]

> 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
$

Les Cargill

unread,
Jun 8, 2012, 7:05:34 PM6/8/12
to
That is actually not a bad argument at all, and probably
close to the truth.

--
Les Cargill

Tim Rentsch

unread,
Jun 8, 2012, 11:30:38 PM6/8/12
to
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.

Joe keane

unread,
Jun 9, 2012, 5:36:29 PM6/9/12
to
In article <jqe0qg$758$1...@dont-email.me>,
Les Cargill <lcarg...@comcast.com> wrote:
>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
0 new messages