const, volatile, etc [was Re: #defines with parameters]

Piercarlo Grandi pcg at aber-cs.UUCP
Tue Dec 13 00:04:35 AEST 1988


It seems that my problem with Doug Gwin is that he cannot conceive that his
rationales can be doubted: if you want signed characters, the only way is
to add a signed keyword, if you want efficient code the only way is a complex
optimizer that relies on volatile.

Since he cannot believe that there can be other approaches, he cannot help
assuming that I have not understood his premises, because my conclusions are
different.  The problem is that I am fully aware of his premises, and still
I have different ones.

In article <9143 at smoke.BRL.MIL> gwyn at brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>)
writes:

    There was never a guarantee that C data had what is now known as the
    "volatile" property.

You mean that nobody explicitly stated the obvious rule that an optimizer
shall not turn a correct program into in incorrect one? Of course! As I said,
C was not designed for optimizing compilers; it was designed as a low level
language, and the very idea that an optimizer could do nasty things behind
the programmer's back was unthinkable.

C is indeed virtually unique in having the register keyword (other languages
allow you to assign variables to specific registers or memory locations,
notably Ada, LIS, Modula-2, Mesa?, but C's register is not like that, of
course), by which the programmer helps the compiler, precisely because the
compiler is not expected assumed or required to have or need an optimizer.

The point here is not to ASSUME that nasty optimization is necessary and
legitimate (and then indeed volatile become necessary to cover your back) the
point is to DEFEND the philosophy under which nasty optimization is necessary
in a language like C that was consciously designed with quite different
assumptions and goals (ever heard this about UNIX and C : simple is beutiful
AND reliable AND easier AND faster AND... or are you a post-V7 guy? :->).

Also, given your belief that Classic C did not explicitly prohibit wanton
caching of non register variables, well, this was what dpANS C ought to be
about, closing loopholes, clarifying that it was never explicitly forbidden
because it was never thought necessary, encouraging the use of register. NOT
introducing volatile. X3J11 has indeed done a fine job in most other areas on
clarifying, closing loopholes, etc...

    Existing compilers in fact give the lie to such a claim.

Then they are buggy! I would like to remind you that C is not what you think
it to be (a close cousin of Ada, a son of BSD), it is what has been defined
to be and used for years and years before a lot of commercial interests saw a
competitive advantage in claiming their compiler would improve sloppy C code;
the world does not begin with dpANS, or with 4.xBSD/S5.x.

    Please cite references for this unique notion of what pre-ANSI C's rules
    were.  So far as I have been able to determine, it was never specified
    one way or another, so by the usual rules for interpreting C rules, this
    would have been an unwise assumption to make.  (Particularly since
    existing implementations did not follow that rule.)

Again, it has never been a usual rule that an optimizer is allowed to turn a
correct program into an incorrect one. If an existing implementation does it,
it is buggy. This volatile argument is as old as programming; every PL/1
programmer knows that many a compiler will generate buggy code when the
optimizer is let loose on code with exception handlers.

They do not think that that is a fault of the language, they rightly think
that it is the compiler that is wrong, and they greatly resent having to use
a compiler option to influence the semantics of a piece of code (ahhhh, if
only PL/1 included volatile for variables, instead of only for procedures! :->).

    "register" is still a supported specifier under ANSI C.  Use it if you
    think your compiler does a poor job of register allocation.

But in any case I still must volatilize all other variables, otherwise the
compiler will do funny things behind my back. Volatile and register are
constrasting approaches to solve the same problem, one is safe and does not
suggest that a complex optimizer is needed, the other is potentially unsafe
and deludes people into buying complex, often unreliable compilers for a
language that was carefully evolved and designed not to require them (and
therein lies one of its beauties, maybe the most important -- otherwise we
would be using Ada or PL/1).

Volatile encourages people to think that a complex optimizer will clean up
their sloppy C code. Too bad that the cleanup cannot be as good as
competently written code, that omitting volatile where it is needed results
in very hard to find bugs, that complex optimizers are themselves, for
obvious reasons, often very buggy.

    The use of "volatile" does not require much analysis.  If you were paying
    attention, I already explained in response to Griff Smith the cases where
    you need to use it.

My dear Doug Gwin, rest assured that your paternalistic innuendo is not
necessary.  I know perfectly well the rationale for "volatile" (enable
optimizations where side effects may occur); I dispute that the only solution
to the problem is "volatile", as I dispute the rationale itself.

I would also like to emphasize that the real big problem will be multi
threaded C code, not signal handlers or device drivers. As any Ada programmer
knows, if you use tasking and fail to stick pragmas volatile/shared wherever
they are needed, maybe in dozens of modules, and that may be a lot of places,
you get into BIG trouble.

    In pre-ANSI C the same problem existed, but there was no standard
    solution for it.

The problem did not exist, because it was unthinkable that the compiler would
do funny things behind your back! If it did, the solutions were:

Debug the compiler! Or, if you could not do that, wrap the reference to the
variable around an asm procedure (which is usually necessary anyway in device
drivers to correctly access device registers, as compilers cannot give the
guarantee that they will generate the exactly right code), as procedures are
all considered "volatile" (in C and almost all other languages I know --
several dozen -- except PL/1 and some AI/Lispish ones).

I would like to add a note (hope it does not start another stream of
misunderstanding, misrepresentation and abuse towards me :->)

    I would like to be able (maybe in C++ ?) to declare a procedure as
    "register", to signify that the values it returns only depend on the
    arguments and not on any globals, and thus it will always return the same
    values given the same arguments.

    Apart from giving a very clever (that, as I said, I do not like) compiler
    a good opportunity to do some caching of procedure's results, it would be
    extremely useful to a mechanical (lint?) or human reader/verifier of the
    code, as it would clearly document which procedures are functions and
    which are generators/closures, an extremely important distinction.
-- 
Piercarlo "Peter" Grandi			INET: pcg at cs.aber.ac.uk
Sw.Eng. Group, Dept. of Computer Science	UUCP: ...!mcvax!ukc!aber-cs!pcg
UCW, Penglais, Aberystwyth, WALES SY23 3BZ (UK)



More information about the Comp.lang.c mailing list