clanguage-lawyerc11standards-compliancec17

If an implementation supports extra nonstandard features, then is such implementation conforming?


Follow-up question for: Do unsupported standard features affect conformance?.

Question: if an implementation supports extra features which are not described in the C standard, nor in any "extension document", then is such implementation conforming?

A simple example: #pragma STDC FP_CONTRACT requires on-off-switch, which is one of ON OFF DEFAULT. However, one implementation in addition to ON OFF DEFAULT does support RESTORE. Hence, such implementation allows writing nonstandard code. Does it mean that such implementation is nonconforming?

Extra question: the C standard tells "what implementation shall/should do". However, does the C standard (or any standard in general) tell "what implementation shall/should not do"? For example, if an implementation does support my_printf (in addition to printf), then is such implementation conforming?


Solution

  • The Standard defines three concepts of conformance. In order of meaningfulness, they are a "Strictly Conforming C Program", a "Conforming C Implementation", and a "Conforming C Program".

    A Strictly Conforming C Implementation is one whose behavior is fully specified by the Standard. This excludes all non-trivial programs for freestanding implementations, since the Standard doesn't define any form of I/O for them. It also excludes many programs that would be portable if the Standard sought to avoid characterizing as UB any actions whose behavior might conceivably be difficult to define on some implementations, or whose behavior might expose the effects of useful optimization.

    A Conforming C Implementation is one which in theory could in theory meaningfully process all Strictly Conforming Programs, but may behave arbitrarily when given any program--strictly conforming or not--that would exceed an implementation's translation limits. That latter caveat creates a loophole big enough to drive a truck through.

    While the Standard requires that an implementation be able to accommodate e.g. 127 nested blocks, 511 block-scope identifiers within a block, 1023 members in a struct or union, and 63 characters in an internal identifier's name, it doesn't require that an implementation be able to accommodate 127 nested blocks, each with 511 identifiers that each identify a structure with 1023 members, each with a name that's 63 characters long. Such a requirement would make the language impossible to support on any translation environment with less than four gigs of storage. To avoid making the language impossible to implement, the Standard refrains from requiring that implementations support arbitrary combinations of translation limits. Instead, all that is necessary for conformance is that there exist some program--possibly a contrived and useless one--which nominally exercises each of the limits, at least individually. The authors acknowledge, in the published Rationale, that such a requirement is absurdly weak:

    The Standard requires that an implementation be able to translate and execute some program that meets each of the stated limits. This criterion was felt to give a useful latitude to the implementor in meeting these limits. While a deficient implementation could probably contrive a program that meets this requirement, yet still succeed in being useless, the C89 Committee felt that such ingenuity would probably require more work than making something useful

    I think they overestimated the "ingenuity" required, but I think the key point is that whether or not the Standard would regard as conforming an implementation that would e.g. allow a program to have one identifier that was 63 characters long and limited all other user identifiers to too characters, nobody who wanted to sell a compiler would impose such a limitation. Thus, while the Standard's definition of "Conforming C Implementation" isn't actually meaningful, it nonetheless establishes some baseline expectations for non-garbage-quality implementations.

    As for the concept of "Conforming C Program", that term is defined to include any program that is accepted by at least one Conforming C Implementation somewhere in the universe. This is obviously too broad to be meaningful; I think the point was that the Committee wanted to avoid categorizing any useful programs as non-conforming. Again from the Rationale (italics original):

    A strictly conforming program is another term for a maximally portable program. The goal is to give the programmer a fighting chance to make powerful C programs that are also highly portable, without seeming to demean perfectly useful C programs that happen not to be portable, thus the adverb strictly.

    C implementations are expressly granted latitude to add extensions to the language, either syntactically or by defining behaviors in situations where the Standard imposes no requirements (typically processing constructs "in a documented fashion characteristic of the environment"), and Conforming (but not Strictly Conforming) C Programs may exploit such extensions. Although implementations are nominally required to produce a diagnostic in response to some such constructs, such a requirement would be satisfied by an implementation that unconditionally outputs: "Warning--this implementation doesn't bother producing diagnostics the author thinks are silly (other than this one)" and programmers would be free to ignore any diagnostics they think are silly.

    It's important to recognize that many practical and useful C programs exploited useful constructs that were widely supported but not universally supportable. Had the Committee sought to characterize as deficient implementations for platforms that could't support such constructs, it would have been rejected by the makers of those platforms. Had it characterized as non-conforming programs that relied upon such constructs, it would have been soundly rejected by the programming community. Thus, as a compromise, it defined a category of "strict conformance" for programs that was sufficiently narrow that failure to meet it could seldom be viewed as a defect, and otherwise relied people wishing to sell compilers to recognize and satisfy the needs of programmers who would be using them--a philosophy that worked well when compiler writers' primary customers were programmers.