[net.lang.c] Type modifiers in C

brooks@lll-crg.ARpA (Eugene D. Brooks III) (10/26/85)

In considering some new type modifiers that are useful for multiprocessing
one needs to consider how type modifiers fit in the ANSI standard.
Could someone explain all the details of what you might do with for example
the volatile type modifier.  For instance does

volatile int foo;	/* Mean that the int foo is volatile. */

int * volatile bar;	/* Mean that bar is a non volatile pointer
			to a volatile int. */

int * volatile cat();	/* Mean that cat returns a pointer to a volatile int. */

volatile int cat();	/* What does this mean? */

volatile int * dog;	/* Mean that dog is a volatile pointer to a
			non-volatile int. */

volatile int * volatile fly;	/* Mean a volatile pointer to a volatile int. */


The draft of the ANSI standard is rather sketchy here and understanding
the semantics clearly would allow one to figure out what to do for the
type modifiers that are being considered.

							Thanks,
							Eugene

bright@dataioDataio.UUCP (Walter Bright) (10/29/85)

In article <943@lll-crg.ARpA> brooks@lll-crg.ARpA (Eugene D. Brooks III) writes:
>Could someone explain all the details of what you might do with for example
>the volatile type modifier.  For instance does
>
>volatile int foo;	/* Mean that the int foo is volatile. */
 YES.

>int * volatile bar;	/* Mean that bar is a non volatile pointer
>			to a volatile int. */
 NO. Bar is a volatile pointer to a non-volatile int.

>int * volatile cat();	/* Mean that cat returns a pointer to a volatile int*/
 NO. Cat() returns a volatile pointer to an int.

>volatile int cat();	/* What does this mean? */
 Cat() returns a volatile int.

>volatile int * dog;	/* Mean that dog is a volatile pointer to a
>			non-volatile int. */
 Dog is a pointer to a volatile int.

>volatile int * volatile fly;	/* Mean a volatile pointer to a volatile int.*/
 YES.

The purpose of the volatile modifier is so that an optimizing compiler
can be told which variables are not candidates for common subexpression
elimination, which ones cannot be put in registers, and which ones are not
candidates for redundant load/store removal. Having a function return
a volatile is not an error, but it doesn't mean much (unless the compiler
is able to deduce that the function call is redundant!).
	My understanding of volatile is that it is a modifier and binds very
tightly. Whether it is left or right associative is not clear.
Such as:

	char * volatile * s;

	<volatile pointer to><pointer to><char>
		-OR-
	<pointer to><volatile pointer to><char>
		??

rcd@opus.UUCP (Dick Dunn) (10/30/85)

> In considering some new type modifiers that are useful for multiprocessing
> one needs to consider how type modifiers fit in the ANSI standard.
> Could someone explain all the details of what you might do with for example
> the volatile type modifier...

...examples follow of various combinations of types and "volatile" at
various points.

I don't have the standard proposal to examine, but there's a general point
about these "type modifiers"--seemingly a generalization of what are more
commonly [mis?]named "storage classes".  There are attributes of objects
which affect the declaration of the object itself but which don't carry
outward, and there are other attributes which have to be propagated to
referencing or containing objects.

Attributes like C's "static" (in the sense that it means "local") and
"external" are used to establish some property of an object at its
declaration, but they don't need to be propagated through, say, a pointer
to the object.  (A pointer to a local int need not be different from a
pointer to a global int.)

Attributes like "constant" or "volatile" need to be propagated through
dependent types.  (A pointer to a volatile int is different from a pointer
to a "normal" int, in the sense that the pointers point to objects which
have different properties; if you dereference the pointers, you have to
treat the resulting objects differently.)

In "current" C (as in K&R), the "static" attribute is particularly
unfortunate in this regard:  When applied to a procedure or a variable
outside of a procedure, it restricts the scope of the object only and there
is no need to propagate the attribute.  When applied to a variable within a
procedure, it affects the semantics and the extent of the variable; in some
sense the static-vs-automatic distinction should be propagated.  (In some
languages it would be prohibited to assign the address of an automatic
variable to a more global pointer--i.e., a pointer whose extent exceeds
that of the variable.)
-- 
Dick Dunn	{hao,ucbvax,allegra}!nbires!rcd		(303)444-5710 x3086
   ...At last it's the real thing...or close enough to pretend.

peter@graffiti.UUCP (Peter da Silva) (11/03/85)

> sense the static-vs-automatic distinction should be propagated.  (In some
> languages it would be prohibited to assign the address of an automatic
> variable to a more global pointer--i.e., a pointer whose extent exceeds
> that of the variable.)

I hope they never put that in 'C'. After all...

	char *myname;
	usage(s)
	char *s;
	{
		fprintf(stderr, "Unknown flag %s.\nUsage: %s ....\n", s, myname);
	}

	main(ac, av)
	int ac;
	char **av;
	{
		...
		myname=av[0];
		...
				usage(av[i]);
	}
-- 
Name: Peter da Silva
Graphic: `-_-'
UUCP: ...!shell!{graffiti,baylor}!peter
IAEF: ...!kitty!baylor!peter

rcd@opus.UUCP (Dick Dunn) (11/04/85)

> > ...(In some
> > languages it would be prohibited to assign the address of an automatic
> > variable to a more global pointer--i.e., a pointer whose extent exceeds
> > that of the variable.)
> 
> I hope they never put that in 'C'. After all...
> 
> 	char *myname;
>	...
> 	main(ac, av)
> 	int ac;
> 	char **av;
> 	{
> 		...
> 		myname=av[0];
> 		...
> 	}

This example would not, in fact, violate the rule given above.  It DOES
represent one of the cases where the rule is difficult to enforce.  If one
were to check the assignment of av[0] to myname, it would be necessary to
know the extent of the object referenced by av.  In the case shown, it's
easy to see; the argument vector exists for the entire execution of the
program.  However, it's hard to establish this, and in some cases you won't
be able to figure it out at compile time.  In that case you can:
	- punt the check, which leaves a hole in what's supposed to be a
	  useful check
	- issue a warning message, annoying everyone without telling them
	  anything that they'll pay attention to
	- reject anything that doesn't obviously meet the constraint, which
	  will rule out some useful, correct programs

Philosophically, the third choice is the easiest for me to buy into, and it
would rule out da Silva's example.  Of course, this would only be happening
in some language other than C, and one might decide in such a language to
make things like the argument and environment string vectors global
variables rather than main-program arguments.  In other words, with
different language rules you just do some things differently.
-- 
Dick Dunn	{hao,ucbvax,allegra}!nbires!rcd		(303)444-5710 x3086
   ...Never attribute to malice what can be adequately explained by stupidity.

savage@ssc-vax.UUCP (Lowell Savage) (11/06/85)

> > > ...(In some
> > > languages it would be prohibited to assign the address of an automatic
> > > variable to a more global pointer--i.e., a pointer whose extent exceeds
> > > that of the variable.)
> > 
> > I hope they never put that in 'C'. After all...
> > 
> > 	char *myname;
> >	...
> > 	main(ac, av)
> > 	int ac;
> > 	char **av;
> > 	{
> > 		...
> > 		myname=av[0];
> > 		...
> > 	}
I think that this rule is talking about something more like one of
the following cases:

	char *cpt;				ffoo()
	...					{	char *cpt;
	foo()						cpt = foo();
	{						...
		char ch[10];			}
		...				foo()
		cpt = ch;			{	char ch[10];
		...					...
	}						return (ch);
						}
the C compiler should catch these (or at least lint should) since
'ch' may go away before the next time cpt is dereferenced.  Now
this should be okay if 'ch' is static, because then it will still
be around no matter when you dereference 'cpt'.  Also, you know
that the only way to get to 'ch' is to call foo, you can't just
use it.  Now if some idiot programmer still wants to muck around
with the data stored in 'ch' by dereferencing 'cpt', that's his
business.  But since (at least one of) the main purpose(s) of foo
is calculate 'ch' it shouldn't depend on any previous data in foo.


These are my own personal biases.  Anyone that wants to share them will
have to fill out a 100-page non-disclosure agreement in octuplicate
(without carbons), send all copies with 2 dollars for processing to
outer Tanzania, wait two years, and chant "Mousy Dung was a bad guy."
five hundred times.  All questions on this matter will be refered to
the Bureau of non-violent violence (BNVV)...or was that the Association
for the Promulgation of Persons Against Associations (APPAA)?

				There's more than one way to be savage
				Lowell Savage