Constant strings

K

Keith Thompson

Ben Bacarisse said:
Keith Thompson said:
Joe Pfeiffer <[email protected]> writes:
So... does anybody know what cdecl does with "array" that making it a
reserved word makes sense? Or is it plain and simply a bug?

It's a reserved word in the English-like syntax it uses to explain
declarations:

cdecl> explain int arr[42]
declare arr as array 42 of int
cdecl> explain int array[42]
syntax error
cdecl>

This *shouldn't* cause it to be reserved for the C-like syntax it uses,
but apparently it treats it that way. I've never looked into the
internals, so I can't be sure what's going on.

cdecl uses the same grammar for both "directions" of it's translation.
'array' is a keyword when used like this:

cdecl> declare arr as array 42 of int
int arr[42]

so it's also one when reading an 'explain' command. You can't name your
array "declare", "explain", "help" or any number of other words that are
considered special. It's a shame, because the error that gets reported
might be confusing. Is it really a syntax error in the declaration, or
did you just use a keyword without knowing?

Even when this is taken into account, cdecl is rather lax in admitting
some things that are not valid C, and rejecting others that are (though
the latter may just be that it has not kept up with recent standards).

It would be an interesting project for someone to clean up cdecl and
release a new version. (Perhaps someone has already done so, but I see
no sign of it at cdecl.org.) I might play around with it myself, but I
honestly don't expect to produce anything worth releasing.

My suggestion: Rather than using a single grammar, recognize the first
word on a line ("declare", "explain", etc.) and use it to determine how
to parse the rest of the line. For bonus points, print more meaningful
error messages than "syntax error".

The source code can be downloaded from:
http://cdecl.org/files/cdecl-blocks-2.5.tar.gz
It apparently hasn't been updated since 1996.

As for licensing, here's an excerpt from the README file, written by
David R. Conrad:

You may well be wondering what the status of cdecl is. So am I.
It was twice posted to comp.sources.unix, but neither edition
carried any mention of copyright. This version is derived from
the second edition. I have no reason to believe there are any
limitations on its use, and strongly believe it to be in the
Public Domain. GNU readline is, of course, covered by the GNU
General Public License.

GNU readline isn't included in the distributed sources, but it links to
it if possible when it's built from source.

One interesting tidbit: cdecl 2.5 treats "noalias" as a keyword.
"noalias" was a proposed keyword, roughly an early attempt at what later
became "restrict", that never made it into the 1989 ANSI C standard.
Dennis Ritchie famously sent an official comment to X3J11 which included
the demand "Noalias must go. This is non-negotiable."
 
B

BartC

Martin Shobe said:
On 4/25/2014 7:31 AM, James Kuyper wrote:

As far as I can tell, the difference is conceptual. A "const array of int"
would mean that the array, as a whole, would be const. An "array of const
int" would mean the each element of the array would be const. I'm unaware
of any practical differences.

'const array' could be allowed to fill an otherwise awkward hole in the type
system, so that every kind of type can have a const attribute.

Structs have similarities to arrays, and there you can have a const struct,
const members (none, any or all), or a combination, including a const struct
with all-const members, without that being reported as redundant.

You might, for example, have a typedef-ed array:

typedef int vector[4];

which you might want to use here:

vector A;

with read-write capabilities; and here:

const vector B = {...};

in read-only mode. For this to happen, the const attribute has to be brought
inside the vector to apply to its element type (without affecting the vector
element of A).

With a const array, this is not necessary; the const attribute is applied to
the element as needed, as it works with structs:

typedef struct {
int a, b;
const int c;
} record;

const record R;

R.a=10; // gcc reports writing to read-only object
R.c=20; // gcc reports writing to read-only member

So const arrays can be read-only arrays, and have a non-const element type,
and the elements can still be protected.
 
S

Stephen Sprunk

James Kuyper said:
I'm talking about your (incorrect) statements of fact about the use
of 'const'. The most prominent of those were your suggestion that
there was some reason why use of 'const' would require insertion of
numerous (const T*) casts.

What was wrong with that idea? It's one way of having 'const' make
itself useful, by effectively providing a write-protect guard on data
being passed to functions that might be writing to the data.

int mydata[...];

SomeFunction(mydata);

This could presumably write all over my data. But:

SomeFunction((const int*)mydata);

This will give a warning, if SomeFunction doesn't have a matching
const (we don't even need to know this). Actually I wasn't advocating
doing this, just complaining that you'd have to go to these lengths
in order for const to be useful.

No, you just have to look at the prototype for SomeFunction(), which you
have to do anyway to know how to properly call it, and see whether its
argument is const or not. If so, you know it won't modify your data; if
not, it might. There is no need for a cast either way.
Nevertheless adding this cast /will/ have that effect. Now you're
saying I am wrong about that?

No, but that cast is pointless and nobody (sane) actually does that.
Those other features used to be just compiler hints; I thought const
was in a different class to those, operating on types so that 'const
T' was distinct from 'T'.

It is, but if you have a program that works correctly with const, then
it would continue to work correctly without const--just like register.

The point is that most programs are _not_ correct, at least at first,
and const helps you find where the problems are--at compile time, rather
than months later when you're trying to debug a program over the phone
with a customer.

S
 
S

Stephen Sprunk

So, what does "const array of int" mean to you? If it were possible to
declare a const array of int, how would you describe the way in which it
differs from an ordinary array of int?


That is the question I'd like answered. I don't understand what people
think they mean by that term that makes it different from "array of
const int".

As previously explained, arrays already seem to be effectively const, so
adding an explicit "const" is a no-op. However, "const array of int"
and "array of const int" read quite differently to me, and IMHO we
shouldn't have two seemingly-different ways of saying the exact same
thing. The latter better expresses both the intent and the behavior, so
it should be the preferred form.

S
 
K

Keith Thompson

BartC said:
'const array' could be allowed to fill an otherwise awkward hole in the type
system, so that every kind of type can have a const attribute.

How is it awkward? What actual benefit would programmers get from
adding "const array"? What syntax would be used to specify a const
array? Could such a syntax be invented that avoids conflicting with the
existing syntax for an array of const elements? Do we really need to
distinct ways of specifying that an array's elements are read-only?

I've been using C for a very long time, and until now I never even
noticed this "awkward hole".
 
B

BartC

Keith Thompson said:
How is it awkward? What actual benefit would programmers get from
adding "const array"? What syntax would be used to specify a const
array? Could such a syntax be invented that avoids conflicting with the
existing syntax for an array of const elements?

I'm not really advocating this. Someone posed a question as to how a const
array can be meaningful, and these are some ideas.
Do we really need to
distinct ways of specifying that an array's elements are read-only?

Going back to my example:

typedef int vector[4];

vector A;
const vector B = {...};

Are the elements of vector const or non-const? See, it's not so obvious!
I've been using C for a very long time, and until now I never even
noticed this "awkward hole".

I notice it all the time. Because you are not allowed to have array types
for expressions, to pass to functions and so on, there's some scene-shifting
done by C to try and pretend they don't exist.

As an example, what's the type of A here:

void somefunction(int A[5]);

and of A here:

int A[5];

which has exactly the same type-spec?
 
K

Keith Thompson

Stephen Sprunk said:
As previously explained, arrays already seem to be effectively const, so
adding an explicit "const" is a no-op.

In what sense are arrays "effectively const"?

An array object is not read-only unless you've included the "const"
keyword in its definition.

If you're talking about the pointer value to which an array
expression is (usually) implicitly converted, that's a pointer,
not an array -- and since it's not an lvalue, "const" doesn't even
apply to it. As I said previously, there's nothing to modify.
"42++" isn't illegal because 42 is const, it's illegal because
42 isn't an lvalue. The same thing applies to the pointer value
resulting from an array-to-pointer conversion.
However, "const array of int"
and "array of const int" read quite differently to me, and IMHO we
shouldn't have two seemingly-different ways of saying the exact same
thing. The latter better expresses both the intent and the behavior, so
it should be the preferred form.

"const array of int" and "array of const int" are not C syntax.

I guess you could draw a distinction between "const int arr[10];"
and "int const arr[10];", but C currently doesn't make such a
distinction. Similarly, "const int n;" and "int const n;" also mean
exactly the same thing. ("int arr const[10];" is a syntax error.)

If you think there are too many ways to express "array of const int"
because the placement of the "const" keyword is too flexible, I won't
disagree, but that's not fixable without breaking existing code.

If you think that "const array of int" is a distinct concept that should
be expressible in C, I ask you to specify what it means and how it
differs from "array of const int".
 
K

Keith Thompson

BartC said:
I'm not really advocating this. Someone posed a question as to how a const
array can be meaningful, and these are some ideas.

(I meant "two", not "to".)
Going back to my example:

typedef int vector[4];

vector A;
const vector B = {...};

Are the elements of vector const or non-const? See, it's not so obvious!

vector is a type. The elements of A are non-const. The elements of
B are const. Try writing "B[0] = 42;" and see what diagnostic you get.

It would be the same if you asked about the members of a const struct
rather than the elements of an array (though for slightly different
reasons).

I'm not 100% certain that a member of a const struct object is
*formally* considered to be "const" (it depends on the exact wording in
the standard, which I'm too lazy to check right now), but the effect is
the same.
I've been using C for a very long time, and until now I never even
noticed this "awkward hole".

I notice it all the time. Because you are not allowed to have array types
for expressions, to pass to functions and so on, there's some scene-shifting
done by C to try and pretend they don't exist.

As an example, what's the type of A here:

void somefunction(int A[5]);

and of A here:

int A[5];

which has exactly the same type-spec?

In the first case, A has type int*. In the second, A has type int[5].

I find this one of the more annoying features of C. I do not defend it;
I merely describe it.
 
K

Keith Thompson

BartC said:
'const array' could be allowed to fill an otherwise awkward hole in
the type system, so that every kind of type can have a const
attribute.
[...]

I forgot to mention: function types can't be "const" either.
 
J

James Kuyper

If you think that "const array of int" is a distinct concept that should
be expressible in C, I ask you to specify what it means and how it
differs from "array of const int".

I've already asked that question twice, and every response has ended up
waffling on the "how does it differ" question:

I suppose a difference could be invented, ...

As far as I can tell, the difference is conceptual. ... I'm
unaware of any practical differences.

My education in advanced physics included learning many apparently
different ways to conceptualized the same physical reality - but if
those different conceptions never produce different predictions, those
differences were not real - the "different" conceptions all
fundamentally mean the same thing, even if that fact isn't obvious.
 
B

Ben Bacarisse

Ben Bacarisse said:
Keith Thompson said:
James Kuyper said:
On 04/24/2014 08:15 AM, BartC wrote:
...
I can't get CDECL to accept 'const array'. That might be a bug in CDECL, but
also in the C type syntax there doesn't seem anywhere to put a const for an
array.

What does CDECL say about

const int array[5];

It says "syntax error", but only because cdecl apparently treats "array"
as a reserved word (arguably a bug in cdecl).

cdecl> explain const int array[5]
syntax error
cdecl> explain const int arr[5]
declare arr as array 5 of const int
cdecl>

I believe that "const" does, at least syntactically, apply to the
element type, not to the array. But there's no practical difference; an
array value consists exactly of the values of the elements, and an array
is read-only if and only if its elements are read-only.

I suppose it depends on what is practical, but there is a difference: a
const array and an array with const elements are not compatible types
(at least that's how I read things).

I am no longer so sure of this. Neither gcc nor clang object to passing

typedef int iarray[3];
const iarray cia;
f(&cia);

to a function, f, with prototype

void f(const int (*a)[3]);

(I use pointers to arrays as the simplest way verify compatibility of
types that decay in other contexts.)

I've tried to give up the kind of close reading of the standard that
would be required to unravel the validity of this so I'll leave it as
something that has no practical consequences.
 
M

Martin Shobe

I've already asked that question twice, and every response has ended up
waffling on the "how does it differ" question:

I was trying to explain what I thought the difference between the two
phrases was. To help do that I also told you something I thought it
wasn't. If that's "waffling" to you, so be it.
My education in advanced physics included learning many apparently
different ways to conceptualized the same physical reality - but if
those different conceptions never produce different predictions, those
differences were not real - the "different" conceptions all
fundamentally mean the same thing, even if that fact isn't obvious.

Not all differences are extensional.

Martin Shobe
 
J

James Kuyper

I was trying to explain what I thought the difference between the two
phrases was.

You gave descriptions that contained different words in different
orders, but I couldn't figure out how they had actual meaningfully
different meanings. That could have been a failure on my part to
understand what you were saying, but for now I still don't understand
the distinction you were making.
... To help do that I also told you something I thought it
wasn't. If that's "waffling" to you, so be it.

Is there something you can do with a const array of int that you can't
do with a array of const int? How about the other way around? It's easy
to come up with answers to those questions if 'array' were replaced with
'pointer', but I have no idea what you think the answers would be for an
array.
 
M

Malcolm McLean

Is there something you can do with a const array of int that you can't
do with a array of const int? How about the other way around? It's easy
to come up with answers to those questions if 'array' were replaced with
'pointer', but I have no idea what you think the answers would be for an
array.
Consider this

const int constarray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int const arrayofconst[10] = { 1 ,2, 3, 4, 5, 6, 7, 8, 9, 10};

int foo( const int const x[5] )
{
return x[0]+x[1]+x[2]+x[3]+x[4];
}

foo(arrayofcont + 5); /* should be legal */
foo(constarray + 5); /*should be illegal */
 
B

BartC

James Kuyper said:
On 04/25/2014 08:06 PM, Martin Shobe wrote:

Is there something you can do with a const array of int that you can't
do with a array of const int? How about the other way around? It's easy
to come up with answers to those questions if 'array' were replaced with
'pointer', but I have no idea what you think the answers would be for an
array.

I was investigating the differences between const structs and const arrays,
and came across these puzzling results:

typedef struct {
const int x;
const int y;
const int z;
} cvector;

typedef struct {
int x;
int y;
int z;
} vector;

int main(void){
cvector a;
const cvector b;
vector c;
const vector d;
int e[3];
const int f[3];

memset(&a,0,sizeof(a)); // No warning ?
memset(&b,0,sizeof(b)); // Warning
memset(&c,0,sizeof(c)); // No warning
memset(&d,0,sizeof(d)); // Warning
memset(&e,0,sizeof(e)); // No warning
memset(&f,0,sizeof(f)); // No warning ?
}

This was compiled with gcc with default options.

The puzzling ones are the attempt to write to a (a struct of all-const
members), which gives no warning here, yet an attempt to assign to a does
so.

And the attempt to write to array f (an array of const int) gives no warning
either.

I understand this all depends on compiler and options used (probably with
enough options set, gcc can be made to reject anything). But with the /same/
set of options, one way to write to an array or struct is allowed, but
another isn't.

What's going on?

(This can interpreted as another dig at the alleged usefulness of 'const',
but it's not; I've lost interest in that argument.)
 
B

Ben Bacarisse

Malcolm McLean said:
Is there something you can do with a const array of int that you can't
do with a array of const int? How about the other way around? It's easy
to come up with answers to those questions if 'array' were replaced with
'pointer', but I have no idea what you think the answers would be for an
array.
Consider this

const int constarray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int const arrayofconst[10] = { 1 ,2, 3, 4, 5, 6, 7, 8, 9, 10};

This might confuse some people -- it's not 100% clear that you are
suggesting a new meaning for this syntax. In C as-it-is, the order of
the type specifiers and qualifiers is irrelevant, so these two
definitions are identical -- the const qualifies the array element
type.

The "thing" that is affected by const changes only when it moves into
what is called the declarator: the syntax that defines pointer, array
and function derived types, so if I wanted to suggest a new syntax to
make the distinction you want I'd use:

int constarray const [10]; // illegal syntax in C as-it-is
int foo( const int const x[5] )
{
return x[0]+x[1]+x[2]+x[3]+x[4];
}

foo(arrayofcont + 5); /* should be legal */
foo(constarray + 5); /*should be illegal */

Why should this be illegal? I don't see anything being modified in a
way that might reasonably be affected by const. If your point is about
type compatibility, why the '+ 5'?
 
M

Malcolm McLean

Why should this be illegal? I don't see anything being modified in a
way that might reasonably be affected by const. If your point is about
type compatibility, why the '+ 5'?
With the first array, the elements are constant. We don't want anyone
messing about with the concept that in our system 1 is the first number
and replacing it with a 0 (or 42). With the second system, the array
is constant. We want ten and only ten numbers from 1 to 10, we don't
want anyone pre-pending a zero or chopping off the ten. Of course C,
like most languages, can't express the concept "this is a datum, not
data, it must be used whole or not at all". But we can at least make a
nod to it by outlawing passing a portion of the array to a subroutine.
 
B

Ben Bacarisse

BartC said:
I was investigating the differences between const structs and const
arrays, and came across these puzzling results:

typedef struct {
const int x;
const int y;
const int z;
} cvector;

typedef struct {
int x;
int y;
int z;
} vector;

int main(void){
cvector a;
const cvector b;
vector c;
const vector d;
int e[3];
const int f[3];

memset(&a,0,sizeof(a)); // No warning ?
memset(&b,0,sizeof(b)); // Warning
memset(&c,0,sizeof(c)); // No warning
memset(&d,0,sizeof(d)); // Warning
memset(&e,0,sizeof(e)); // No warning
memset(&f,0,sizeof(f)); // No warning ?
}

This was compiled with gcc with default options.

The puzzling ones are the attempt to write to a (a struct of all-const
members), which gives no warning here, yet an attempt to assign to a
does so.

And the attempt to write to array f (an array of const int) gives no
warning either.

I understand this all depends on compiler and options used (probably
with enough options set, gcc can be made to reject anything). But with
the /same/ set of options, one way to write to an array or struct is
allowed, but another isn't.

What's going on?

The compiler is simply taking the easy option and obeying the minimal
rules of the language. In the two cases that puzzle you, the type of
the pointer 'target' is not const, so the pointers can be converted to
const void * (that memset wants) with no problem.

There are lots of things the compiler could help with. For example, a
compiler could tell you that you are in trouble after writing

cvector a;
const vector b;

because these are not initialised and you can now can't alter them
without invoking undefined behaviour.

Also, in the last case, it is more normal to simply pass f, rather than
&f, and in that case you would get a diagnostic.

<snip>
 
B

BartC

James Kuyper said:
On 04/24/2014 05:37 AM, BartC wrote:

More accurately, such conversions do not occur implicitly at all. The
diagnostic message is side-effect of the fact that the conversion did
NOT occur. It is the use of a const-qualified type in a context where it
is incompatible with the required type, that is the actual cause of the
constraint violation.

My statement is not quite right in the case of matching function parameters.
(I didn't follow your comments well enough to know if you are pointing out
the same thing).

It seems to be more of a problem to pass const T to T when T is some pointer
type (const T* to T* when the pointer-ness is expressed directly).

It's not an issue to pass a 'const int' argument to an 'int' parameter for
example (otherwise a huge amount of code would run into problems.). Because
the callee can do what it likes to its copy without affecting the caller's
version.

(This could finally be an example of a difference between const arrays and
arrays of const, *if* arrays could be passed by value.

A const array *could* be passed to a matching non-const array parameter as
it would be immune from changes just like the const int argument is.

But an array of const elements probably wouldn't match an array of
non-consts; although the caller's version is safe, the array type would
suggest that the elements cannot be assigned to; an implicit conversion to
non-const would override that.)
 
B

BartC

Ben Bacarisse said:
int e[3];
const int f[3];
memset(&e,0,sizeof(e)); // No warning
memset(&f,0,sizeof(f)); // No warning ?
Also, in the last case, it is more normal to simply pass f, rather than
&f, and in that case you would get a diagnostic.

Yes, this was an oversight due to just copying the code for structs.

Presumably, f has type 'pointer to const int', so it is easy to see that
this pointer could be used to write to a const.

But &f has type 'pointer to array of const int' so is not so obvious.

(And which might finally be a way for const arrays to differ from arrays of
consts, and to assert their usefulness: 'pointer to const array of int' is
also a pointer with an obvious const target.)
 

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
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top