volatile, noalias and optimization

Pablo Halpern pablo at polygen.uucp
Fri Apr 29 10:33:37 AEST 1988


> It's been pointed out at some length that the new /volatile/ and /noalias/
> keywords are really all about controlling the optimizer in various C
> implementations, more than about the language itself.

No, volatile is not all about controlling the optimizer.  It's just that
code that needs volatile is MORE LIKELY to break when optimized.  It might
break on some compilers without optimization.  In fact, volatile has
less to say about optimization than does register.

I think a lot of the debate about the necessity of volatile comes from
a lack of understanding about how many subtleties there are in defining
the semantics of a language.

To show why volatile is really necessary, let me first show why the
"assume all variables are volatile" argument is a semantic nightmare.
Take the following code:

1 main()
2 {
3	int a, b;
4
5	scanf("%d", &a);
6	b = 2*a;
7	printf("%d\n", b);
8 }

Assume I run this program and type the number 5 at the keyboard.  Would you
have any hesitation about claiming that this program would produce "10"
as its output?  No? So you wouldn't have any problem with the compiler
optimizing this as:

	scanf("%d", &a);
	printf("%d\n", 2*a);

would you?  Of course not!  But if b is assumed volatile, you cannot
assume it has the same value in line 7 as it was assigned in line 6.
Even if you were to restrict the optimizer, do you really want the
program not to mean what it seems to mean?  You see, its not just the
optimizer that needs variables to be non-volatile.  Its needed by both
humans and machines for giving meaning to a program.  Thus, making all
variables effectively volatile not only makes the program harder to
optimize, it acually changes the semantics of the language such that
almost nothing can be expressed in it.

So, variables should not be volatile by default.  "Why not use a #pragma
to show the exceptions, instead of adding a keyword." you ask.  "After
all, the use of shared memory and device registers is non-portable anyway, 
right?"

Wrong.  The use of these things can be as portable as writing to a file.
The fopen() function from the standard library returns a handle that
can be used by portable programs to write to a file.  The implementation
of fopen() is not portable, but the function call itself its.  The
vender of your C compiler isolated the non-portable stuff so that you
could call your program "portable."

Similarly, let's assume a set of functions that have non-portable
implementations but whose interfaces are portable and well-defined.
The function, shared_malloc() returns a pointer to a named piece of
shared memory and the functions begin_mutex() and end_mutex() guarentee
mutually exclusive access to that memory.  The following code
would be impossible without volatile:

	int volatile *shared;	/* pointer to volatile int */

	shared = (int *) shared_malloc("foo", 10 * sizeof(int));
	while (should_fill()) {
		begin_mutex(shared);
		if (shared[0] == 0)
			fill_array(shared);
		end_mutex(shared);
	} /* end while */

This type of code could be scattered throughout a 10,000 line program.
The program is portable except for the three functions mentioned.  If
volatile were not standard, this program could not be written portably
at all.

"But that's multi-tasking and C is not a multi-tasking language."
You'd better get use to the fact that multi-tasking is becoming a
bigger and bigger port of a programer's life.  Even personal computers
are beginning to multi-task and these tasks sometimes need to communicate.
Signal and interupt handlers are examples of multi-tasking in an
otherwise single-task environment.

But unlike the ill-fated noalias, you CAN program in C without understanding
or using volatile while giving those of us that write system software
a way to write portable code.

FLAME ON
	I'm also sick of people implying that any program that is not
	strictly conforming is totally non-portable.  I write a lot of
	programs that are portable to a large number of machines but
	are not portable to ALL machines.  I also write a lot of programs
	that have small, self-contained, sections that handle non-portable
	things like shared memory allocation, interupt handling, semaphores,
	etc..  Volatile would allow me to keep these sections small and
	isolated because the program could "admit" that it might be
	running in a multi-tasking environment.  As it is, I'm already
	playing it a bit dangerous when it comes to signal handlers.

	If volatile were a #pragma, then every compiler could choose its
	own syntax and semantics for it, if it were implemented at all.
	Even among Unix systems, code that used volatile would not be
	portable!  Then maybe IEEE would have to get into the act and
	define a superset of ANSI C (called POSIX C?) which specifies
	a standard syntax for the volatile #pragma.  Yuk!
FLAME OFF

Thankfully, it looks like volatile is here to stay.  Thankfully, it looks
like noalias has bit the dust!

Pablo Halpern		|	mit-eddie \
Polygen Corp.		|	princeton  \ !polygen!pablo  (UUCP)
200 Fifth Ave.		|	bu-cs      /
Waltham, MA 02254	|	stellar   /



More information about the Comp.lang.c mailing list