Path: utzoo!attcan!uunet!lll-winken!lll-lcc!ames!haven!adm!smoke!gwyn From: gwyn@smoke.BRL.MIL (Doug Gwyn ) Newsgroups: comp.std.c Subject: Re: __STDC__ and non-conforming ANSI C compilers Message-ID: <9422@smoke.BRL.MIL> Date: 18 Jan 89 20:53:45 GMT References: <9391@smoke.BRL.MIL> <8731@megaron.arizona.edu> <9405@smoke.BRL.MIL> <860@auspex.UUCP> Reply-To: gwyn@brl.arpa (Doug Gwyn (VLD/VMB) ) Organization: Ballistic Research Lab (BRL), APG, MD. Lines: 203 In article <860@auspex.UUCP> guy@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 or , for example. That doesn't mean that 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 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 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, 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 as default behavior. Given the way _POSIX_SOURCE ended up being specified, any POSIX application that requires fdopen() MUST #define _POSIX_SOURCE before including . (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.