Array sizes and const

M

Malcolm McLean

בת×ריך ×™×•× ×¨×שון, 3 ביוני 2012 21:49:19 UTC+1, מ×ת Ben Bacarisse:
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;
}
 
M

Malcolm McLean

בת×ריך ×™×•× ×¨×שון, 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.
 
I

Ian Collins

בת×ריך ×™×•× ×¨×שון, 3 ביוני 2012 22:08:01 UTC+1, מ×ת Ian Collins:
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?
 
B

BartC

Ian Collins said:
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.

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

Ian Collins

Ian Collins said:
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.
 
M

Malcolm McLean

בת×ריך ×™×•× ×¨×שון, 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.
 
I

Ian Collins

בת×ריך ×™×•× ×¨×שון, 3 ביוני 2012 23:55:33 UTC+1, מ×ת Ian Collins:
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.

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

BartC

Ian Collins said:
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.)
 
I

Ian Collins

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

BartC

Ian Collins said:
On 06/ 4/12 11:23 AM, BartC wrote:

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

Ian Collins

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

Ah, I see your point. The rest of my reply still applies!
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.
 
B

Ben Bacarisse

Malcolm McLean said:
בת×ריך ×™×•× ×¨×שון, 3 ביוני 2012 21:49:19 UTC+1, מ×ת Ben Bacarisse:
typedef struct
{
char *name;
} EMPLOYEE;

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

What's that got to do with what you said? The object being modified by
strcpy is not a member of *employee.
 
B

Ben Bacarisse

Ian Collins said:
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>
 
I

Ian Collins

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

Ben Bacarisse

BartC said:
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.
 
M

Malcolm McLean

בת×ריך ×™×•× ×©× ×™,4 ביוני 2012 00:14:38 UTC+1, מ×ת Ian Collins:
On 06/ 4/12 11:04 AM, Malcolm McLean wrote:

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

BartC

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

Jens Gustedt

Am 04.06.2012 13:20, schrieb BartC:
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
 
J

James Kuyper

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

Alan Curry

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.
 

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