From: torek@horse.ee.lbl.gov (Chris Torek)
Newsgroups: comp.unix.bsd
Subject: Re: mktemp - Bus Error.
Date: 6 Nov 1992 12:29:24 GMT
Organization: Lawrence Berkeley Laboratory, Berkeley
Reply-To: torek@horse.ee.lbl.gov (Chris Torek)
NNTP-Posting-Host: 128.3.112.15

In article <1992Nov5.180007.28471@fcom.cc.utah.edu> terry@cs.weber.edu
(A Wizard of Earth C) writes:
>Several compilers treat:
>	char tmpname[] = "/tmp/foo.XXXXXX";
>as if it were:
>	char *tmpname = "/tmp/foo.XXXXXX";

Any compiler that does so is horribly broken.

>...the second is, of course, legal.

The first is also legal, provided that:

 a) the compiler claims to be ANSI X3.159-1989 (`ANSI C') conformant; or:
 b) the array "tmpname" has static duration.

(This is an inclusive `or'.)

>	char *foo = "Hello World" + 6;
>
>	printf( "%s\n", foo);		/* prints "World\n"*/
>	printf( "%s\n", foo - 6);	/* depends on code generation*/

This is entirely wrong.  The type of a string literal is now and has
always been `array N of char'.  (There have been a few compilers that
got this wrong, but they were/are broken and essentially irrelevant.
No BSD compiler has been broken in this way.)  The characters
themselves may be kept in read-only storage---this is the default under
GCC, and is permitted by the ANSI C standard---or in read/write
storage.  The old PCC-based BSD compilers did the latter, and GCC will
also do so if you use `-fwritable-strings'.  Writable string literals
are permitted by the ANSI standard---it does not pin implementations
down either way---but since they *might* be read-only, you should
treat them as read-only.

Note that the "/tmp/foo.XXXXXX" in

	char tmpname[] = "/tmp/foo.XXXXXX";

is *NOT* a string literal, despite the syntactic resemblance.  (It is
an initializer.)

>... If the compiler generates code the K&R/Portable C compile way, the
>second printf() will print "Hello World\n"; otherwise, what it does is
>not defined (for instance, Microsoft C).

If MicroSoft C version x.y does not print "Hello World\n", MicroSoft C
version x.y is broken.  (This would come as no surprise to anyone who
has ever tried to use MicroSoft C for large projects.  Note that a
broken compiler can still be useful.  The two are not entirely
orthogonal, but neither are they mutually contradictory.)

>... you should be able to use:
>
>	char	*p;
>
>	p = mktemp( "/tmp/foo.XXXXXX");
>
>without ill effect.

Not so.  If the characters are kept in read-only storage, as permitted
by the ANSI standard, this constitutes an attempt to modify a
non-modifiable object.  The result is, according to the ANSI standard,
undefined.  A bus error and core dump is a perfectly valid result.

The compiler cannot diagnose an error here because the type of a
string literal is `array N of char', not `array N of read-only char',
even when the individual `char's are read-only.  This is a consequence
of ANSI C's type compatibility rules: if the type of the array were
`const char [N]', code of the form:

	char *space = " ";

would require a diagnostic.  (This could have been avoided by adding
special case rules, or by allowing `const char *q; p = q;', but the
members of X3J11 did neither.)

GCC nevertheless allows you to obtain a warning anyway: the
`-Wwrite-strings' option tells the compiler to use the const qualifier
for string literal types.  This is not strictly conformant---although
there is no way to tell, since compilers may issue bogus warnings at
any time without violating the ANSI standard---and will, as the manual
warns, merely be a nuisance unless you are *really* picky about using
const qualifiers, but there it is.  (You might also want to use
`-Wcast-qual'.)
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 510 486 5427)
Berkeley, CA		Domain:	torek@ee.lbl.gov