Questions about const

O

omni

Something like

int const * const * const * const ippp = &ipp;

compiles fine. Does that mean * can be replaced by * const
at any place, i.e. pointer can be replaced by const ptr?

So you can have expressions of any complexity with const ptrs?
Obviously you can only have one basetype being const.

There is no difference between const int x;

and int const x;

is there?

The examples in the Microsoft documentation all talk about const ptr
to const int, and nothing more involved than that, but my reading
shows any pointer within a declaration can be replaced by const ptr,
although for expressions beyond one level of indirection I could not
see what would be the point, you would rarely see that sort of
declaration.
 
P

Peter Nilsson

Something like

int const * const * const * const ippp = &ipp;

compiles fine.

It would depend on what ipp's type is.
Does that mean * can be replaced by * const
at any place, i.e. pointer can be replaced by const ptr?
No.

So you can have expressions of any complexity with const ptrs?

Potentially yes, but see below.
Obviously you can only have one basetype being const.

I don't know what you mean by this. An object is either const
qualified or it isn't. The type of object being pointed to is
recursively subject to the same rule.

A function parameter can be const qualified and accept a non-
const qualified argument. However, this only applies to the
parameter, not to the pointed to type in the case of pointer
parameters.
There is no difference between const int x;

and int const x;

is there?

No. This has been answered quite recently.

The problem with const pointers is that they can quite easily
lead to 'const poisoning'.

Consider...

int **new_matrix(size_t rows, size_t columns);

void add_matrices( int **result,
size_t r1, size_t c1, const int **m1,
size_t r2, size_t c2, const int **m2);

void foo(void)
{
int **a = new_matrix(3,4);
int **b = new_matrix(4,5);
int **c = new_matrix(3,5);
...initialisation of a and b...
add_matrices(c, 3, 4, a, 4, 5, b);
...
}

The add_matrices call requires a diagnostic since **a is not
constant qualified, but **m1 is const qualified. More precisely
a is not assignment compatible with m1. [Note, a diagnostic
needn't be phrased as an 'error', but might only be a
'warning'.]

A correct alternative declaration would be...

void add_matrices( int **result,
size_t r1, size_t c1, int * const *m1,
size_t r2, size_t c2, int * const *m2);

....but this doesn't specify that the individual int elements of
the matrix are const, only that the pointers to the columns are!

Logical correctness requires...

void add_matrices
(
int **result,
size_t r1, size_t c1, const int * const *m1,
size_t r2, size_t c2, const int * const *m2
);

....but then, due to the constraints of C, we are required to
cast a and b in our calls...

add_matrices(c,
3, 4, (const int * const *) a,
4, 5, (const int * const *) b );

The reason for the introduction of const into C was to increase
the type strength of the language. Original C did not have const
qualified objects. If an object wasn't to be modified, then it
was the programmer's responsibility to see that it wasn't! [Of
course, this is still true today to an extent.]

However, from the above examples, it should be clear that const
is not a perfect solution in guarding against such programmer
errors.
 
O

omni

It would depend on what ipp's type is.


No.

But within an ordinary variable declaration, surely * can be replaced
by * const at any place? Can you give an example where that is not the
case (not relating to function's const parameters, just a variable
declaration)?

A function parameter can be const qualified and accept a non-
const qualified argument. However, this only applies to the
parameter, not to the pointed to type in the case of pointer
parameters.

I didn't know C allows const qualiified function parameters. I thought
that was a C++ feature only. Which C standard would that be, it isn't
in C89 is it?

int **new_matrix(size_t rows, size_t columns);

void add_matrices( int **result,
size_t r1, size_t c1, const int **m1,
size_t r2, size_t c2, const int **m2);

void foo(void)
{
int **a = new_matrix(3,4);
int **b = new_matrix(4,5);
int **c = new_matrix(3,5);
...initialisation of a and b...
add_matrices(c, 3, 4, a, 4, 5, b);
...
}

The add_matrices call requires a diagnostic since **a is not
constant qualified, but **m1 is const qualified. More precisely
a is not assignment compatible with m1. [Note, a diagnostic
needn't be phrased as an 'error', but might only be a
'warning'.]

Microsoft C does not give a diagnostic, and I don't see why it should.
Surely you can assign a into m1, since you are taking a variable
quantity and assigning it into a constant parameter, so that the
function addmatrices will not be able to change it... which shouldn't
be a problem.

The other way round, if you assign a constant to a variable, mucho
problemo, as with the following;


const int **new_matrix(size_t rows, size_t columns);

void add_matrices( int **result,
size_t r1, size_t c1, int **m1,
size_t r2, size_t c2, int **m2);

void foo(void)
{
const int **a = new_matrix(3,4);
const int **b = new_matrix(4,5);
const int **c = new_matrix(3,5);

add_matrices(c, 3, 4, a, 4, 5, b);

}

because if you assign a constant into a variable, without explicit
casting, then the variable can change the "constant" value.

I have not used const (at all!!!) in my applications. What I'm really
interested in is whether function parameters are now allowed to have
the const qualifier, because my C89 textbook doesn't mention that.
 
C

Christian Kandeler

But within an ordinary variable declaration, surely * can be replaced
by * const at any place?
Yes.

I didn't know C allows const qualiified function parameters. I thought
that was a C++ feature only. Which C standard would that be, it isn't
in C89 is it?

Sure it is. And they are all over the place, too: Just look at some library
functions that take pointer arguments. Whenever the object pointed to is
not to be changed by the function, the parameter is const qualified.
int **new_matrix(size_t rows, size_t columns);

void add_matrices( int **result,
size_t r1, size_t c1, const int **m1,
size_t r2, size_t c2, const int **m2);

void foo(void)
{
int **a = new_matrix(3,4);
int **b = new_matrix(4,5);
int **c = new_matrix(3,5);
...initialisation of a and b...
add_matrices(c, 3, 4, a, 4, 5, b);
...
}

The add_matrices call requires a diagnostic since **a is not
constant qualified, but **m1 is const qualified. More precisely
a is not assignment compatible with m1. [Note, a diagnostic
needn't be phrased as an 'error', but might only be a
'warning'.]

Microsoft C does not give a diagnostic, and I don't see why it should.
Surely you can assign a into m1, since you are taking a variable
quantity and assigning it into a constant parameter

No, he is not. The function parameter is not constant: it is a (non-const)
pointer to a pointer to a const int, and the argument is a pointer to
pointer to (non-const) int. These types are not comapatible. While it is
possible to assign, for example, an int* to a const int* (as described in
6.3.2.3.2 in the Standard), this rule is _not_recursive. You need a cast to
convert int** to const int**.


Christian
 
O

omni

No, he is not. The function parameter is not constant: it is a (non-const)
pointer to a pointer to a const int, and the argument is a pointer to
pointer to (non-const) int. These types are not comapatible. While it is
possible to assign, for example, an int* to a const int* (as described in
6.3.2.3.2 in the Standard), this rule is _not_recursive. You need a cast to
convert int** to const int**.

I don't understand why it is possible to assign int* to const int*
but not to assign int** to const int**

Can you explain why this is so, please?

Is there a general algorithm for determining assignment compatibility
between types which contain const qualifiers?

Finally... Where can I obtain the ANSI Standard, in print form,
preferably annotated? Which annotated version would be best?
thank-you....
 
C

Chris Torek

I don't understand why it is possible to assign int* to const int*
but not to assign int** to const int**

Can you explain why this is so, please?

The short answer is "because the rules say so". A longer (and
arguably better) answer is that this opens a hole in const-safety;
however, that would leave the question of why you cannot assign it
to "const int *const *". (You can do the latter in C++, but not
in C, and the only answer remaining is "because the rules say so".)

See below for an example of "sneaking around const".
Is there a general algorithm for determining assignment compatibility
between types which contain const qualifiers?

Yes, it is in the C standards. (Not all that helpful, I know, but
that is where you get the definitive answers!)
Finally... Where can I obtain the ANSI Standard, in print form,
preferably annotated? Which annotated version would be best?
thank-you....

See the comp.lang.c FAQ.

Example (from Lawrence Kirby, very slightly modified):

const int i = 1;
const int *cp = &i;

int *p;
const int **pp = &p; /* error in C; but suppose it were OK */

*pp = cp; /* since pp points to p, *pp is p, so now p = cp */
*p = 0; /* this would change i */

See the entire thread at:
<http://groups-beta.google.com/group/comp.lang.c/browse_thread/thread/4de50f05fc5ee69>
(watch out for URL wrap).
 
C

CBFalconer

.... snip ...

Finally... Where can I obtain the ANSI Standard, in print form,
preferably annotated? Which annotated version would be best?

The only known annotated form is by Schildt, for C90, and out of
print, and the annotations are known to be totally worthless, along
with most other bull-schildt. Now if you could persuade Chris
Torek to write an annotated version ......

Earlier today I spotted a Schildt C book in B&N, sporting a Rev 3
on the cover. A quick peek inside did reveal several "int
main(void)" headings, so he has learned something. However a
further flip revealed "while (!feof(f)) {....", so he has learned
very little.
 
L

lawrence.jones

Chris Torek said:
however, that would leave the question of why you cannot assign it
to "const int *const *". (You can do the latter in C++, but not
in C, and the only answer remaining is "because the rules say so".)

Which is because no one has yet figured out exactly what the rules need
to be to allow all of the safe operations without allowing any of the
unsafe operations. The C++ rules can't be used for C because the C++
laguage is specified differently than the C language and because C99 has
additional type qualifiers that aren't covered by the C++ rules.
Lacking correct rules, the committee felt that safe but occasionally
inconvenient rules were better than convenient but occasionally unsafe
rules.

-Larry Jones

Oh, now don't YOU start on me. -- Calvin
 
R

Richard Bos

pete said:
Is C99, ANSI?

It had better; it's ISO. It's hardly unheard of for the USA not to
honour an international agreement of any kind, of course :-/ But yes,
AFAIK ANSI has ratified C99 as well.

Richard
 
P

pete

Richard said:
It had better; it's ISO. It's hardly unheard of for the USA not to
honour an international agreement of any kind, of course :-/ But yes,
AFAIK ANSI has ratified C99 as well.

Thank you.
 
K

Keith Thompson

pete said:
Is C99, ANSI?

That depends on what you mean by "ANSI" as an adjective.

The term "ANSI C", starting in the late 1980s, has been used to refer
to the 1989 ANSI C standard (mostly to distinguish it from the earler
version of the language defined in K&R1). In 1990, ISO issued its own
C standard, and ANSI ratified it. Since the 1990 ISO C standard is
essentially identical to the 1989 ANSI C standard (the section numbers
differ, but it describes the same language), it was reasonable to use
the term "ANSI" to refer to either standard.

In 1999, ISO issued a new standard, which ANSI also ratified.

So, if by "ANSI C" you mean the C standard produced by ANSI, C89 is
arguably the only one that qualifies. If by "ANSI C" you mean the
standard ratified by ANSI, that's C99; I believe ANSI itself
acknowledges that its own C89 standard has been superseded by C99.
(That's assuming I've gotten all the above details right.)

Yes, this is all annoyingly nitpicking, but I'm afraid it's relevant.
The phrases "ANSI C", "ISO C", and "Standard C" are all genuinely
ambiguous, since C99 is the current official standard, but the C90
standard is still widely used. There may be an official unambiguous
definition of each phrase, but there are still plenty of people who
use them all in inconsistent ways. It's quite possible that the OP
didn't know all this history, and may have been unclear on what he
meant by "the ANSI standard".

When it matters, we should refer to C89, C90, or C99, not to ANSI C or
ISO C. When someone else refers to ANSI C or ISO C, we can often
infer from context which standard is being refered to, but we should
make that inference explicit (as Richard Bos did above).

In an ideal world, of course, all C implementations would have been
upgraded to C99 conformance by now, and the C89 and C90 standards
would be only of historical interest.
 
W

Walter Roberson

In an ideal world, of course, all C implementations would have been
upgraded to C99 conformance by now, and the C89 and C90 standards
would be only of historical interest.

Alas, in the real world, old COBOL programmers were receiving premium
wages in 1999 because there was so much code that had been barely
upgraded over a 40 year span.
 
S

S.Tobias

Which is because no one has yet figured out exactly what the rules need
to be to allow all of the safe operations without allowing any of the
unsafe operations. The C++ rules can't be used for C because the C++
laguage is specified differently than the C language

In C++ the semantics for `volatile' are explicitly intended to be
the same as in C. For `const' with POD types they are basically the
same I believe (slight differences are orthogonal to conversions).
I don't see any differences in both languages that would prevent
accepting C++ qualification conversion rules for these two qualifiers
in C. Do you have any example to the contrary?
and because C99 has
additional type qualifiers that aren't covered by the C++ rules.

The only additional qualifier is `restrict', which is a specialty,
as it does not refer to the type itself (like `volatile') but
rather taints expressions (ie. expressions inherit restrict-ness
by assignment from other expressions blessed with `restrict').
I'm not aware of any language constraints on assignment between
`restrict' and non-`restrict' pointers (misuse results in UB);
it means there is nothing to "protect" (unlike `const'). I don't
have any deep thoughts on this, but it seems to me that `restrict'
qualification could be completely ignored in first and higher levels
(0-th level refers to the identifier) during conversions.

I think (I might be wrong here, so please correct me) that `restrict'
qualification has virtually no meaning in higher levels:
// typedef int * [restrict] pint_t;
pint_t p;
restrict int **pp = &p; /* C might require cast */
`restrict' in `pp' declaration doesn't matter for object access
through pp (**pp). What matters is whether the type `pint_t'
is restrict or not (ie. whether the object `p' is restrict or not).

The (un)safety of `restrict' usage is not attached to the type system.


Were there any discussions about `restrict' in the above context?
Do you have any example, similar to the one explaining assignment
of (int**) to (const int**)?
 
L

lawrence.jones

S.Tobias said:
In C++ the semantics for `volatile' are explicitly intended to be
the same as in C. For `const' with POD types they are basically the
same I believe (slight differences are orthogonal to conversions).

Yes, that's the intent.
I don't see any differences in both languages that would prevent
accepting C++ qualification conversion rules for these two qualifiers
in C. Do you have any example to the contrary?

The problem is not a difference between the languages but rather that
the terminology and concepts used to describe the languages in the
relevant standards are significantly different such that transliterating
the rules appropriately is a non-trivial task. As I recall, arrays were
a particularly tricky bit.

-Larry Jones

Who, ME? Who?! Me?? WHO... Me?! Who, me??? -- Calvin
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,161
Messages
2,570,892
Members
47,431
Latest member
ElyseG3173

Latest Threads

Top