[comp.lang.c] const comparison in C and C++

schmidt@beaver.ics.uci.edu (Doug Schmidt) (09/15/88)

Hi,

   Would someone please explain to me the rationale behind C++'s
allowance of ``const's'' objects for use with specifying array size
declarations, as opposed to ANSI-C's reject of this construct?  For
example, the following is legal C++:

----------------------------------------

const int Bar = 100;
int Foo[Bar]; // declares an array of 100 ints

----------------------------------------

However, this does not work with the ANSI-Cesque compilers I've 
tried (gcc, for example).  I'm interested to know the conceptual
differences between the two languages on this point.

thank you,

   Doug Schmidt

gwyn@smoke.ARPA (Doug Gwyn ) (09/15/88)

In article <709@paris.ICS.UCI.EDU> schmidt@beaver.ics.uci.edu (Doug Schmidt) writes:
>I'm interested to know the conceptual
>differences between the two languages on this point.

Essentially, C++ "const" means "constant"; ANSI C "const" means "readonly".

bs@alice.UUCP (Bjarne Stroustrup) (09/15/88)

Doug Schmidt of University of California, Irvine - Dept of ICS writes:

 > Hi,
 > 
 >    Would someone please explain to me the rationale behind C++'s
 > allowance of ``const's'' objects for use with specifying array size
 > declarations, as opposed to ANSI-C's reject of this construct?  For
 > example, the following is legal C++:
 > 
 > ----------------------------------------
 > 
 > const int Bar = 100;
 > int Foo[Bar]; // declares an array of 100 ints
 > 
 > ----------------------------------------
 > 
 > However, this does not work with the ANSI-Cesque compilers I've 
 > tried (gcc, for example).  I'm interested to know the conceptual
 > differences between the two languages on this point.
 > 
 > thank you,
 > 
 >    Doug Schmidt

``const'' was introduced into C++ for three reasons:

	(1) to provide better documentation of interfaces
		(In particular, consts as argument types showing that
		the value of objects would not change within a function)
	(2) to enable the greater use of symbolic constants
		(In particular, integer consts that do not need to be
		allocated as objects unless the programmer explicitly
		requires it by declaring a const `extern' or taking its
		address) This ties in with a desire to reduce the use
		of macros significantly. Note that C++ also introduced
		inline functions.
	(3) to enable use of read only memory for large constant structures
		such as the tables produced by YACC.

The first two reasons was by far the most important to me at the time.
I can only conjecture about the reasons of the ANSI committe, but my reading
of the rumors and the various versions of the definition of `const' in the
ANSI drafts is that originally they latched on to the third reason exclusively
and that over the years the ANSI C definition of const moved slowly towards
the original conception.

Both the ANSI C and the C++ versions of `const' falls a bit short of the ideal
(as is common for programming language features), but the C++ version retains
the concept that unless stated otherwise a const is a relatively local entity
that might be `optimized away' and a valid alternative to a #define or and
enumerator in a header file.

In ANSI C a `const' default has external linkage so you have to allocate
storage for it (just in case) and a `const' may not be used in a constant
expression.

maart@cs.vu.nl (Maarten Litmaath) (09/17/88)

In article <8500@smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
\Essentially, C++ "const" means "constant"; ANSI C "const" means "readonly".

Aha! That means the following is correct?

const volatile int * const clock;	/* clock is a readonly pointer to */
					/* a readonly and volatile int    */
-- 
    Alles klar,                       |Maarten Litmaath @ Free U Amsterdam:
                   Herr Kommissar?    |maart@cs.vu.nl, mcvax!botter!maart

bs@alice.UUCP (Bjarne Stroustrup) (09/17/88)

 Free U Amsterdam writes:

brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
 > Essentially, C++ "const" means "constant"; ANSI C "const" means "readonly".
 > 
 > Aha! That means the following is correct?
 > 
 > const volatile int * const clock;	/* clock is a readonly pointer to */
 > 					/* a readonly and volatile int    */

Yes. In both languages.

gwyn@smoke.ARPA (Doug Gwyn ) (09/18/88)

In article <1411@solo3.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes:
>In article <8500@smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>\Essentially, C++ "const" means "constant"; ANSI C "const" means "readonly".
>Aha! That means the following is correct?
>const volatile int * const clock;	/* clock is a readonly pointer to */
>					/* a readonly and volatile int    */

The "const"s mean that you code is not permitted to modify the contents
of the variable "clock", nor to modify the int data by indirection via
the pointer found in "clock".  (The "volatile" means that the contents
of the location found by indirection through "clock" are subject to
change by agents outside the C virtual machine model, which prevents
gung-ho optimizers from picking up the value once then using it ever
after without ever fetching it again.)

The above declaration at "file scope" would be rather pointless as it
calls for "clock" to be initialized with a null pointer, and since you
can't subsequently modify it, there's not much point in having it.  In
an actual application presumably you would supply a suitable address
for the initializer.

C "const" basically constrains the means of access, so that for example
	void copy(const char *source, char *destination, unsigned count);
is a useful declaration for a function that is guaranteed not to alter
storage via its first parameter.  However, assuming this represents a
block-move function, the destination range is allowed to overlap the
source range, because modification of any storage validly accessible via
the second parameter is NOT prohibited.

If you think about the consequences for code generation when compiling
the definition of this example function, it should be clear that one
significant class of program bugs can be (must be!) detected AT COMPILE
TIME, without adding run-time overhead.  That is why this was a suitable
addition to C; it fits "the spirit of C".  It did take a few iterations
to get the specification straightened out.

bill@proxftl.UUCP (T. William Wells) (09/18/88)

In article <1411@solo3.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes:
: In article <8500@smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
: \Essentially, C++ "const" means "constant"; ANSI C "const" means "readonly".
:
: Aha! That means the following is correct?
:
: const volatile int * const clock;     /* clock is a readonly pointer to */
:                                       /* a readonly and volatile int    */

Almost.  As specified, it is not initialized and so contains a
null pointer.  You should initialize it to the right address.

---
Bill
novavax!proxftl!bill

bill@proxftl.UUCP (T. William Wells) (09/18/88)

In article <8516@smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
: C "const" basically constrains the means of access, so that for example
:       void copy(const char *source, char *destination, unsigned count);
: is a useful declaration for a function that is guaranteed not to alter
: storage via its first parameter.  However, assuming this represents a
: block-move function, the destination range is allowed to overlap the
: source range, because modification of any storage validly accessible via
: the second parameter is NOT prohibited.

Sorry Doug, it's undefined.  (And, drat, I get to fix a, guess
what, COPY FUNCTION, where I made this same mistake.  :-)

From section 3.5.3:

"If an attempt is made to modify an object defined with a
const-qualified type through use of an lvalue with
non-const-qualified type, the behavior is undefined."

---
Bill
novavax!proxftl!bill

gwyn@smoke.ARPA (Doug Gwyn ) (09/19/88)

In article <785@proxftl.UUCP> bill@proxftl.UUCP (T. William Wells) writes:
>In article <8516@smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>:       void copy(const char *source, char *destination, unsigned count);
>: ... modification of any storage validly accessible via
>: the second parameter is NOT prohibited.
>Sorry Doug, it's undefined.

Sorry yourself, it's the way I stated.

>"If an attempt is made to modify an object defined with a
>const-qualified type through use of an lvalue with
>non-const-qualified type, the behavior is undefined."

This is simply not relevant.  The parameter declarations do not define
objects.

So long as the object being block-moved into does not have the "const"
attribute, it can be modified.  The point is that a pointer-to-const
can ALSO be used to refer to such a non-const object, but it cannot be
used to modify the object.

davidsen@steinmetz.ge.com (William E. Davidsen Jr) (09/20/88)

In article <782@proxftl.UUCP> bill@proxftl.UUCP (T. William Wells) writes:

| :
| : const volatile int * const clock;     /* clock is a readonly pointer to */
| :                                       /* a readonly and volatile int    */
| 
| Almost.  As specified, it is not initialized and so contains a
| null pointer.  You should initialize it to the right address.

  Am I misreading the standard? My interpretation was that uninitialized
global storage was set to *all bit zero* and that there was something
that mentioned this might not be zero for types other than integral
types. Is the compiler and linker path really supposed to initialize
this to a null pointer (as in zero cast to a pointer)? On some machines
the NULL pointer isn't all bits off, for sure.
-- 
	bill davidsen		(wedu@ge-crd.arpa)
  {uunet | philabs}!steinmetz!crdos1!davidsen
"Stupidity, like virtue, is its own reward" -me

gwyn@smoke.ARPA (Doug Gwyn ) (09/21/88)

In article <12184@steinmetz.ge.com> davidsen@crdos1.UUCP (bill davidsen) writes:
>  Am I misreading the standard? My interpretation was that uninitialized
>global storage was set to *all bit zero* and that there was something
>that mentioned this might not be zero for types other than integral
>types.

Other way around.  When initializers aren't specified for data having
static storage duration, the initial contents are zero (of the
appropriate type), not 0-bit patterns.  On several architectures this
distinction has no practical significance, but on some it does.

bill@proxftl.UUCP (T. William Wells) (09/22/88)

In article <8529@smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
: In article <785@proxftl.UUCP> bill@proxftl.UUCP (T. William Wells) writes:
: >In article <8516@smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
: >:       void copy(const char *source, char *destination, unsigned count);
: >: ... modification of any storage validly accessible via
: >: the second parameter is NOT prohibited.
: >Sorry Doug, it's undefined.
:
: Sorry yourself, it's the way I stated.
:
: >"If an attempt is made to modify an object defined with a
: >const-qualified type through use of an lvalue with
: >non-const-qualified type, the behavior is undefined."
:
: This is simply not relevant.  The parameter declarations do not define
: objects.

I see what you mean.  I didn't interpret the "defined with" when
reading the section.  And I'm not *too* sorry because this means
I don't have to go and fix up that copy routine (and a few
others) in our library.  :-)

---
Bill
novavax!proxftl!bill