__STDC__ and non-conforming ANSI C compilers

Doug Gwyn gwyn at smoke.BRL.MIL
Thu Jan 19 06:53:45 AEST 1989


In article <860 at auspex.UUCP> guy at auspex.UUCP (Guy Harris) writes:
>Would putting a recommendation in the Rationale that non-conforming
>implementations not define __STDC__ at all help?

Well, it might have been a good idea, but I'm sure the X3J11 Redactor
(who advised AT&T to #define __STDC__ 0) would object, and perhaps
the Rationale editor wouldn't agree to do it unless so directed by
committee vote.  Also I don't think any additional editorial work is
planned; the proposed Standard and Rationale have been submitted to
X3 already.

>if you stick a "#else" in there at that level, what goes between it
>and "#endif"?

Whatever is already going on in the existing pre-ANSI C implementation.
The reason we needed a standard was that this was pretty much a random
approximation to what K&R seemed to be saying, plus various additional
inventions done wildly differently by different implementors.  There is
no logical way to stretch anything from the new (proposed) Standard to
cover the existing behavior, and I think it is a mistake to try.

>If the the question really can't be answered meaningfully, I don't see
>that "#if __STDC__" is a useful test; the only useful tests I could see
>would be something such as
>	#if __STDC__ == 2
>	#define	NOALIAS	noalias
>	#elif __STDC__ == 1
>	#define	NOALIAS
>	#endif
>once the second ANSI C standard comes out after all the problems noted
>with "noalias" have been solved :-).

That is indeed one possible use for values of __STDC__.

The problem is NOT in the __STDC__==1 (or ==2, etc.) domain;
it's in the unstandardized domain, for which __STDC__ simply
does not help -- it's not even defined in most of the environments
I currently have to port code to, and having it defined as 0 would
help me not one bit.  I do rely on __STDC__ to determine whether to
use <stdarg.h> or <varargs.h>, for example.  That doesn't mean that
<varargs.h> necessarily exists in a non-standard environment, but
if it doesn't I can probably cons up an implementation and add it
to the local extensions to the environment.  The point is that I
am supposed to be able to RELY on <stdarg.h> in an environment that
indicates that it is standard-conforming.  The question is, how do
I test in my source code for that, using __STDC__?  I e-mailed a
detailed examination of the alternatives to Dave Prosser of AT&T;
the bottom line is that a PARANOID programmer is advised to write
	#ifdef __STDC__
	#if __STDC__ > 0
	#define MY_STDC_INDICATOR 1
	#endif
	#endif
then use MY_STDC_INDICATOR instead of __STDC__, if he is unable to
trust the vendors to leave __STDC__ alone.  Even that won't defend
against really stupid preemption of __STDC__ by the vendors, but I
was unable to figure out ANY guaranteed meaningful use of __STDC__
in such a case.  On the implementor's side, assuming he wishes to
support use of __STDC__ in SOME useful way by applications, his best
strategies (in non-conforming mode) turn out to be either: leave
__STDC__ undefined or define it as 0.  (Other choices were all
clearly suboptimal.)  Either of these choices would be acceptable for
paranoid programs (which would use the technique described above as
the best bet against the widest range of vendor strategies).  However,
against simpler programming techniques such as
	#ifdef __STDC__
or
	#if __STDC__
one or another vendor choice (for the non-conforming mode) would be
better than the other.  It should be noted that the second program
test just given fails in some existing C implementations ("use of
undefined symbol in preprocessing expression"), so in fact many
programmers may be tempted to use the first form.  If they do so,
then __STDC__ defined as 0 causes the wrong branch to be taken in
compiling the source code; whether or not that is benign depends on
which "ANSI C" features the code is trying to exploit and whether or
not they are available in the non-conforming case.  Apparently some
vendors think that such conditionalization will always be done to
take advantage of features that are available even in their __STDC__-
equal-to-0 case, but I dispute that.  (I gave Dave a simple example
to the contrary.)

>Now one form of "strict ANSI non-compliance" (i.e., the negation of
>"strict ANSI compliance") that could be useful would be that exhibited
>by an implementation that conforms to ANSI C except for POSIX items that
>might get in the way.

There weren't supposed to be any of these!  As inheritor of the role
of 1003.1/X3J11 liaison, I'm painfully aware of that; read on...

The main problem seems to be that vendors want to include their old
extra UNIX cruft in <stdio.h> without requiring their customers to
use a different form of compilation from the ANSI C mode.  Even 1003.1
wants to do this.  I don't think that is even possible.  So then the
question becomes, how to most readily make one compiler serve both
environments AND the new POSIX environment.  That really requires two
bits of information to properly select all possible cases.  ANSI C
__STDC__ is apparently being relied on to switch on the "ANSI C or not"
bit.  _POSIX_SOURCE, a late invention to try to resolve the name space
conflicts in standard headers that define things for both ANSI C and
POSIX, was specified backward from what X3J11 had recommended;
consequently vendors such as AT&T have decided that it is not suitable
for use as the other selection bit and are trying to overload __STDC__
for this.  _POSIX_SOURCE, specified as being supplied by the
APPLICATION, not the implementation, was specified as turning OFF
POSIX-permitted extensions, but what was really needed was a way to
turn ON ANSI C-prohibited extensions, which is not at all the same
thing, and in any event the vendors don't want to tell their customers
to #define _POSIX_SOURCE in order for their existing code to compile.

The simplest solution would have been:
	cc	# backward-compatible sloppy UNIX mess version
	acc	# ANSI-conforming version
	pcc	# POSIX- and ANSI-conforming version
	fcc	# like "pcc" but with extra ANSI-prohibited stuff.
	
Presumably all four would predefine various secret __names then
invoke common compiler passes, perhaps with additional flags to turn
on Reiserisms in cpp etc.  What I would have for the two names known
to the programmer in each of the four cases are:
	cc	__STDC__ not defined
	acc	__STDC__==1
	pcc	__STDC__==1
	fcc	__STDC__ not defined

I think AT&T has in mind the use of __STDC__==0 in the "fcc" case
instead of coming up with their own secret symbols, and merging
"cc" and "fcc" together into one case, and "acc" and "pcc" into a
second case.  Given the _POSIX_SOURCE botch such a merged "acc/pcc"
would still have to require applications to #define _POSIX_SOURCE,
not only to turn off unconstrained POSIX extensions, but also to
turn ON POSIX conformance.  (That's the "compromise" position as it
emerged from the liaison work; I'll be the first to admit that it is
only technically a solution to the conflict, not practically.)  Thus
I don't think it advisable to actually merge the four cases into two.

>For instance, <stdio.h> would probably define "ferror" as a macro.
>Doing so breaks ANSI compliance, as I understand it; ...

NO!  Nearly all ANSI C functions can be implemented as macros, IF
they are "safe" macros (evaluate their argument exactly once) AND
there is also a genuine function in the C library (in case the
programmer wants to use a pointer to it).

>... with "portable" meaning "portable to POSIX-conformant systems"
>rather than "portable to ANSI C-conformant systems. 

But POSIX-conformant systems are supposed to be ANSI C-conformant
also, unless they are specifically advertised as "Common Usage C"
versions.  This means that a (POSIX+ANSI C)-conformant implementation
CANNOT declare fdopen() in <stdio.h> as default behavior.  Given the
way _POSIX_SOURCE ended up being specified, any POSIX application that
requires fdopen() MUST #define _POSIX_SOURCE before including
<stdio.h>.  (In fact, I would argue that ALL applications HAVE TO
#define _POSIX_SOURCE in order to meet the letter of the POSIX spec.)
It would be nice if one of the supported compiler invocations ("pcc"
in my list above) would predefine _POSIX_SOURCE (which ANSI C DOES
allow) so that one wouldn't need to edit source files to accomplish
this (and would only need to change the definition of "CC" in one's
master Make.config).  That would be far more useful than the apparent
choice of compilation environments AT&T seems to be heading toward.

>POSIX does not, as I remember, require ANSI C conformance; ...

What it does require is that any implementation that doesn't conform
to the C Standard shall clearly so state.  The two choices are:
	C Standard Language-Dependent System Support
	Common Usage C Language-Dependent System Support
(Technically, the use of cross-reference to sections of the C Standard
is pointless unless the POSIX implementation is ANSI C conformant,
because the C Standard does not constrain non-conforming
implementations IN ANY WAY.  But this is just a legality and was not
actually intended to be interpreted that way.)

>One possibility for these #ifdef might be specific names for particular
>functions; unfortunately, there's no standard for those names, so the
>writer can't assume something and hope for the best.  Unfortunately,
>alternatives involving __STDC__ have the problems you list.  I don't
>think there's anything that POSIX defines that says "this implementation
>is ANSI C, with the exception of this specified list of extra goobers in
>the namespace"; if there isn't, it's too late to fix it in POSIX.

No, there's nothing like that.  Only _POSIX_SOURCE even comes close.

>The best I see that could be done here is to make a strong
>recommendation that POSIX vendors define
>__ANSI_C_EXCEPT_FOR_POSIX_STUFF__ (or some other specified name) to
>match what __STDC__ would have been defined as had the "allow POSIX
>stuff" flag not been given to the compiler.

Practially ANY de facto standard not involving __STDC__ would be fine
so far as I'm concerned.  As it stands, we have no satisfactory
solution.  I suggest that "pcc" mean "POSIX and almost ANSI C conforming
with the symbol _POSIX_SOURCE predefined for your convenience" (the
only deviation from ANSI C conformance being the extra POSIX stuff in
the standard headers) and that "acc" mean "ANSI C conforming".  "cc"
should mean "our closest approximation to the cc you were already using,
except for possible compatible extensions".  I don't think there is any
practical need for a "POSIX and ANSI C conforming" invocation of the
compiler; "pcc" should be good enough.

It's really unfortunate that 1003.1 didn't straighten out more of the
name space problems historical UNIX has had.



More information about the Comp.std.c mailing list