What are the Constraints in Standard C?

2019-01-22 19:18发布

问题:

C standards talk about constraints, e. g. ISO/IEC 9899:201x defines the term

constraint
restriction, either syntactic or semantic, by which the exposition of language elements is to be interpreted

and says in chapter Conformance

If a ‘‘shall’’ or ‘‘shall not’’ requirement that appears outside of a constraint or runtime-constraint is violated, the behavior is undefined.

In chapter Environment, Subsection Diagnostics it is said

A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or implementation-defined.

So, it is important to know what are the constraints in C, for example for compiler writers to judge when diagnostics are required, or for C programmers when diagnostics rather than just undefined behaviour can be expected.
Now, there are sections all over the standard document with the title Constraints, but I cannot find definitive wording as to what exactly the term constraint covers in the standard.

  • Are the constraints everything that appears in the sections titled Constraints?
  • Is every requirement that is stated outside of those sections not a constraint?
  • Is there a comprehensive description of constraint in the standard that I missed?

回答1:

Are the constraints everything that appears in the sections titled Constraints?

In the sense of n1570 3.8 (a restriction imposed on programs which requires a conforming implementation to issue a compile-time diagnostic message when violated), I think yes.

Is every requirement that is stated outside of those sections not a constraint?

In the sense of 3.8, I think yes, but for a more circular reason: The standard's structure is fairly formal. Whenever applicable there seems to be an explicit Constraints section. Therefore I understand that by definition anything which is not in a Constraints section is not a constraint in the sense of 3.8.
There are a few "shall" clauses outside Constraints sections which appear completely compile-time enforceable, cf. below for a few examples. They are often in adjacent Semantics sections. I may be missing subtleties which prevent compile-time detection in the general case (so that a diagnosis cannot be made mandatory), or perhaps the standard is not completely consistent. But I would think that a compiler could simply translate a violating program, exactly because the requirements are not in a Constraints section.

Is there a comprehensive description of constraint in the standard that I missed?

I think 3.8 is all you get. I try to explore the term below and agree that the definition is unsatisfying.


I looked deeper into the standard to find that out. Here is my research.

The term constraint

Let's start with the basics. The definition of "constraint" in 3.8 which you quote is surprisingly hard to understand, at least without context ("restriction, either syntactic or semantic, by which the exposition of language elements is to be interpreted"). "Restriction" and "constraint" are synonyms, so that the rewording doesn't add much; and what is meant by "exposition of language elements"?? Exposition is a word with several meanings; let's take "writing or speech primarily intended to convey information" from Dictionary.com, and let's assume they mean the standard with that. Then it means basically that a constraint in this standard is a constraint of what is said in this standard. Wow, I wouldn't have guessed that.

Constraints as per 3.8

Pragmatically just examining the actual Constraints sections in the standard shows that they list compile time restrictions imposed on conforming programs. This makes sense because only compile-time constraints can be checked at compile time. These additional restrictions are those which cannot be expressed in the C syntax.1

Constraints outside Constraints sections

Most uses of "shall" outside of Constraints sections impose restrictions on a conforming implementation. Example: "All objects with static storage duration shall be initialized (set to their initial values) before program startup", a job of a conforming implementation.

There are a few "shall" clauses imposing restrictions on a program (not the implementation) outside of Constraints sections though. I would argue that most fall in the same category as the "runtime constraints [...] on a program when calling a library function" mentioned in 3.18. They seem to be run time constraints which are not generally detectable at compile time (so that diagnostics can not be mandatory).

Here are a few examples.

In 6.5/7 n1570 details the much-debated aliasing rules:

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:

  • a type compatible with the effective type of the object
  • a qualified version of a type compatible with the effective type of the object, [...]

In 6.5.16.1, "Simple Assignment":

If the value being stored in an object is read from another object that overlaps in any way the storage of the first object, then the overlap shall be exact[..]."

Other examples concern pointer arithmetic (6.5.6/8).

Shall clauses which could be in Constraints sections

But then there are other shall clauses whose violation should be detectable at compile time; I would not have blinked if they had appeared in the respective Constraints section.

  • 6.6/6, "Cast operators in an integer constant expression shall only convert arithmetic types to integer types" (under "Semantics"); what can you detect at compile time if you cannot detect types of constants and casts?
  • 6.7/7, "If an identifier for an object is declared with no linkage, the type for the object shall be complete by the end of its declarator" (under "Semantics"). To me is seems to be a basic compiler task to detect whether a type is complete at some point in the code. But of course, I have never written a C compiler.

There are a few more examples. But as I said, I would think that an implementation is not required to diagnose violations. A violating program which manages to sneak past the compiler simply exposes undefined behavior.


1 For example, I understand that the syntax doesn't deal with types -- it only has generic "expressions". Therefore every operator has a Constraints section detailing the permissible types of its arguments. Example for shift operators: "Each of the operands shall have integer type." A program which is trying to shift the bits of a float is violating this constraint, and the implementation must issue a diagnostic.



回答2:

The C committee addressed this issue in the response to Defect Report # 033. The question in that defect report was:

Is a conforming implementation required to diagnose all violations of ''shall'' and ''shall not'' statements in the standard, even if those statements occur outside of a section labeled Constraints?

The author of that defect report suggested a couple of possible alternative ways of interpreting the language of the standard. The second alternative he listed said (in part):

Syntax rules are those items listed in the Syntax sections of the standard. Constraints are those items listed in the Constraints sections of the standard.

Part of the committee's response was:

Suggested Interpretation #2 is the correct one.

I believe that covers your questions fairly completely, but just to state answers to your questions more directly:

  • Are the constraints everything that appears in the sections titled Constraints?
  • Is every requirement that is stated outside of those sections not a constraint?

A "constraint" is a requirement that is stated in a section explicitly marked "Constraints". Any requirement stated outside such a section is not a constraint.

  • Is there a comprehensive description of constraint in the standard that I missed?

At least as far as I know, the standard itself doesn't contain a more specific statement about what is or isn't a constraint, but the linked defect report does.



回答3:

Are the constraints everything that appears in the sections titled Constraints?

It appears they are mostly (there are some cases which are not, fx: it's stated that "Incrementing is equivalent to adding 1" in one of the constraint sections).

Is every requirement that is stated outside of those sections not a constraint?

I haven't seen a "constraint" outside those sections.

Is there a comprehensive description of constraint in the standard that I missed?

Probably not, if there were an authoritative such it would be in the standard and probably be the "constraint" sections (and explicitly mentioned that these are all "constraints").

My interpretation is that the chapter 3 should be interpreted so that every use of the defined terms would have the meaning defined in that section. Especially everywhere the term "constraint" is used it should be understood according to your first quote.

Your second quote is no exception. It's noted in the definition of the term "constraint" that there is no requirement that the constraint is explicitely termed a constraint. This means that you have to determine if it's a "constraint" by checking if it's a such restriction.

However there seem to be quite a few examples of "shall" and "shall not" that could be taken to be such restrictions without explicitely termed as such. That would leave all the occurrences "shall" and "shall not" be mandating or prohibiting a certain behavior of the implementation - and if these are not fulfilled, then yes the behavior may be undefined (since you're using an implementation that doesn't conform to the standard).

It looks like all that fits the definition of "constraint" seem to occur under a "constraint" section, and everything in the "constraint" sections seem to be "constraints".



回答4:

Are the constraints everything that appears in the sections titled Constraints?

Yes. Every syntactic and semantic restrictions mentioned in the standard are constraints.

For example, a constraint on Constant expressions (C11-6.6/3):

Constant expressions shall not contain assignment, increment, decrement, function-call, or comma operators, except when they are contained within a subexpression that is not evaluated.115)

Therefore, the constant expressions

3 = 5;
10++;

shows constraint violation.

Note that in this case shall requirement as well as constraint both are violated.

Is every requirement that is stated outside of those sections not a constraint?

For standard conforming C, yes. A shall requirement on integer constant expression (C11-6.6/6):

An integer constant expression117) shall have integer type [...]

For example, an integer constant expression is required for size of a non-variable length array. Therefore,

int arr[5+1.5];

violates the shall requirement. The type of expression 5+1.5 is not integer type. This shall requirement is out of constraint.

It should be noted that a shall requirement may be a constraint too.



回答5:

In my work in requirements engineering, the words "constraint" and "requirement" have different scope. It is important, also for the standard, to define those explicitly. I searched the word "constraint" in the standard and it seems I may draw the following conclusion:

A constraint is a limitation of either the input (pre-condition) or the output (post-condition) of the behavior the section of the standard describes. For input it means the input must adhere to the constraint (e.g. argc shall be positive). For output it means it must satisfy the constraint for any following unit of the standard to have a well-defined input (its pre-condition).

A requirement is part of the specification of the behavior of the section of the standard. "Shall" is a positive description of what is required; "shall not" is generally a limitiation, but not a constraint - it may participate though in meeting a constraint on its output.

Constraints and requirements can be seen as "external interfaces" (the constraints) and "system behavior/processing" (the requirements).

Shall generally denotes a requirement (a phrase without "shall" is hence not a requirement). "Shall" used in a constraint is then either used to define the input or output (e.g. argc shall be positive) or specifies behavior concerning validating the constraint (e.g. "...shall give a diagnostic message").

Strictly speaking, "shall" used in specifying behavior of validating an input constraint should not be listed in the constraint section (should not be listed in the interface specification) but in a processing section (behavior section).

Note that there can be no validation of an output constraint as the output should adhere to the specification; only a next uit can check those constraints if they are in its input constraints.

This may be a personal view but it seems to fit the uses of these words in the standard.



回答6:

constraint

restriction, either syntactic or semantic, by which the exposition of language elements is to be interpreted

This means that every explicit restriction for program logic or syntax set by the c standart in any way is a constraint. This includes syntactic constraints (e.g. Blocks must be terminated with a ;) and semantic constraints (e.g. You shall not use a variable before initializing it), basicly everything that is either syntacticly (notation-wise) or semanticly (usage of correct notation-wise) not allowed or defined as not allowed (undefined behaviour).

Is every requirement that is stated outside of those sections not a constraint?

I do think that all explicit requirements for the programming in the C language fall either under a syntactic or semantic constraint.

Is there a comprehensive description of constraint in the standard that I missed?

Not to my knowledge.