标准 C 中的约束是什么?

What are the Constraints in Standard C?

C 标准谈​​论约束,e。 G。 ISO/IEC 9899:201x 定义术语

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

并在一致性

一章中说

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

环境一章中,诊断小节中提到

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.

因此,重要的是要知道 C 中的约束是什么,例如编译器编写者判断何时需要诊断,或者对于 C 程序员何时可以预期诊断而不仅仅是未定义的行为。
现在,整个标准文档中都有标题为 Constraints 的部分,但我找不到关于术语 constraint 涵盖的确切措辞标准。

constraint

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

这意味着 c 标准以任何方式对程序逻辑或语法设置的每个显式限制都是约束。这包括句法约束(例如,块必须以 ; 结尾)和语义约束(例如,在初始化变量之前不得使用它),基本上所有在句法(符号方面)或语义(使用正确的符号)不允许或定义为不允许(未定义的行为)。

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

我确实认为 C 语言编程的所有显式要求都属于句法或语义约束。

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

据我所知。

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

是的。标准中提到的每一个句法和语义限制都是约束。

例如,对常量表达式的约束 (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)

因此,常量表达式

3 = 5;
10++;

显示约束冲突。

请注意,在这种情况下 shall 要求以及 constraint 都被违反了。

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

对于符合标准的 C,是的。 整数常量表达式 (C11-6.6/6) 的要求:

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

例如,非可变长度数组的大小需要整数常量表达式。因此,

int arr[5+1.5];

违反了必须的要求。表达式 5+1.5 的类型不是整数类型。此 要求不受限制。

需要注意的是,shall 要求也可能是一个约束条件。

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

似乎大部分是(有些情况不是,fx:在其中一个约束部分中声明 "Incrementing is equivalent to adding 1")。

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

我没有看到 "constraint" 在这些部分之外。

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

可能不会,如果有这样的权威,它会在标准中并且可能是 "constraint" 部分(并明确提到这些都是 "constraints")。

我的解释是第 3 章应该被解释为每次使用定义的术语都具有该节中定义的含义。特别是在使用术语 "constraint" 的任何地方,都应该根据您的第一句话来理解。

你的第二句话也不例外。在术语 "constraint" 的定义中指出,不要求将约束明确称为约束。这意味着您必须通过检查它是否是这样的限制来确定它是否是 "constraint"。

然而,似乎有很多 "shall" 和 "shall not" 的示例可以被视为此类限制,而无需明确说明。这将使所有出现的 "shall" 和 "shall not" 强制或禁止实施的某种行为 - 如果这些没有实现,那么是的,行为可能是未定义的(因为你正在使用实施不符合标准)。

看起来符合 "constraint" 定义的所有内容似乎都出现在 "constraint" 部分下,而 "constraint" 部分中的所有内容似乎都出现在 "constraints" 中。

在我的需求工程工作中,"constraint" 和 "requirement" 这两个词有不同的范围。对于标准来说,明确定义这些也很重要。我在标准中搜索了"constraint"这个词,似乎可以得出以下结论:

A constraint 是标准部分描述的行为的输入(前提条件)或输出(post-条件)的限制.对于输入,这意味着输入必须遵守约束条件(例如 argc 应为正)。对于输出,这意味着它必须满足标准的任何后续单元的约束才能具有明确定义的输入(其前提条件)。

要求是标准部分行为规范的一部分。 "Shall"是对要求的正面描述; "shall not" 通常是限制,但不是约束 - 它可能参与满足其输出的约束。

约束和要求可以看作是"external interfaces"(约束)和"system behavior/processing"(要求)。

Shall 通常表示要求(没有 "shall" 的短语因此不是要求)。约束中使用的 "Shall" 然后用于定义输入或输出(例如 argc 应为正数)或指定有关验证约束的行为(例如“...应给出诊断消息”) .

严格来说,"shall"用于指定验证输入约束的行为不应列在约束部分(不应列在接口规范中),而应列在处理部分(行为部分)。

请注意,无法验证输出约束,因为输出应符合规范;如果它们在其输入约束中,则只有下一个 uit 可以检查这些约束。

这可能是个人观点,但似乎符合这些词在标准中的用法。

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

在 n1570 3.8 的意义上(对程序施加的限制,要求符合要求的实现在违反时发出编译时诊断消息),我认为是的。

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

在 3.8 的意义上,我认为是的,但出于更循环的原因:该标准的结构相当正式。只要适用,似乎就有一个明确的 Constraints 部分。因此我明白 根据定义 任何不在 Constraints 部分中的东西都不是 3.8.
意义上的约束 在 Constraints 部分之外有一些 "shall" 子句,它们看起来完全是编译时可执行的,参见。下面举几个例子。它们通常位于相邻的 Semantics 部分。我可能遗漏了在一般情况下阻止编译时检测的细微之处(因此无法强制进行诊断),或者标准可能不完全一致。但我认为编译器可以简单地翻译一个违规程序,正是 因为 要求不在 Constraints 部分。

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

我认为 3.8 就足够了。我尝试探索下面的术语并同意该定义不令人满意。


我更深入地研究了标准以找到答案。这是我的研究。

术语约束

让我们从基础开始。您引用的 3.8 中 "constraint" 的定义出奇地难以理解,至少在没有上下文的情况下("restriction, either syntactic or semantic, by which the exposition of language elements is to be interpreted")。 "Restriction" 和 "constraint" 是同义词,因此改写并没有增加太多; "exposition of language elements" 是什么意思?? Exposition 是一个有多种含义的词;让我们从 Dictionary.com 中获取 "writing or speech primarily intended to convey information",并假设它们指的是标准。那么基本上就是说这个标准里面的一个constraint就是这个标准里面说的一个约束。哇,我不会猜到的。

约束 根据 3.8

务实地检查标准中的实际 Constraints 部分表明它们列出了 强加于符合 程序的编译时间限制 . 这是有道理的,因为在编译时只能检查编译时约束。 这些额外的限制是那些不能用 C 语法表达的限制。1

约束 部分

之外的约束

大多数 "shall" 在 约束 部分之外的使用 对符合要求的 实现 施加限制。 示例:"所有具有静态存储持续时间的对象都应初始化(设置为它们的 初始值)在程序启动之前”, 符合规范的实现工作。

有几个 "shall" 子句在 Constraints 部分之外对 program(不是实现)施加了限制.我认为大多数与 3.18 中提到的 "runtime constraints [...] on a program when calling a library function" 属于同一类别。它们似乎是 运行 时间限制,通常在编译时无法检测到(因此不能强制进行诊断)。

这里有几个例子。

在 6.5/7 n1570 中详细介绍了备受争议的别名规则:

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, [...]

在 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[..]."

其他示例涉及指针运算 (6.5.6/8)。

Shall 子句可以在 Constraints 部分

但是还有其他 shall 子句,其违规行为应该在编译时检测到;如果它们出现在相应的 Constraints 部分,我不会眨眼。

  • 6.6/6, "整数常量中的强制转换运算符 expression should only convert arithmetic types to integer types"(under "Semantics");如果你不能检测常量和强制转换的类型,你能在编译时检测到什么?
  • 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"(在"Semantics"下)。对我来说,这似乎是一项基本的编译器任务,用于检测代码中某个类型是否完整。但是当然,我从来没有写过C编译器。

还有几个例子。但正如我所说,我认为诊断违规行为不需要实施。设法偷偷通过编译器的违规程序只会暴露未定义的行为。


1 例如,我知道语法不处理类型——它只有泛型 "expressions"。因此每个运算符都有一个 Constraints 部分详细说明其参数的允许类型。移位运算符示例:"Each of the operands shall have integer type." 试图移位浮点数位的程序违反了此约束,实施必须发出诊断。

C 委员会在对 Defect Report # 033 的回复中解决了这个问题。该缺陷报告中的问题是:

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?

该缺陷报告的作者提出了几种解释标准语言的可能替代方法。他列出的第二个备选方案说(部分):

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.

委员会的部分回应是:

Suggested Interpretation #2 is the correct one.

我相信这相当完整地涵盖了您的问题,但只是为了更直接地回答您的问题:

  • 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" 是明确标记为 "Constraints" 的部分中规定的要求。在此类部分之外陈述的任何要求都不是约束。

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

至少据我所知,标准 本身 不包含关于什么是或不是约束的更具体的声明,但链接的缺陷报告确实如此.

标准中约束的目的是指定条件,在这些条件下,需要符合要求的实现才能发出诊断,或者允许实现可以在没有约束的情况下以与要求相反的方式处理程序这样做可能比其他指定的行为更有用。尽管严格符合 C 程序不允许违反约束(任何违反约束的程序都不是严格符合 C 程序),但此类限制不适用于旨在符合但不严格符合的程序。

C 标准是作为多个重叠派系之间的折衷而编写的,包括

  1. 那些认为它应该阻止程序员编写不能在所有平台上互换工作的代码的人
  2. 认为它应该允许以已知平台为目标的程序员利用他们需要支持的所有平台共有的功能,即使这些功能并非在所有平台上都受支持
  3. 那些认为应该允许编译器诊断结构和动作的人,这些结构和动作比故意的意图更经常地执行
  4. 那些认为它应该允许程序员做一些事情的人,比如执行地址计算,这看起来是错误的,但如果按照指定的方式精确执行,就会产生程序员期望的对象的地址。

为了在这些群体之间达成共识,该标准对在严格符合 C 程序中可以做的事情施加了限制,但也将符合 C 程序的定义写得足够广泛,以至于几乎没有有用的程序会被标记为非- 无论它们所依赖的扩展多么模糊,都符合要求。如果源代码构造会违反可诊断的约束,但实现的客户无论如何都会发现它有用,那么该实现可能会输出其客户可以忽略的诊断(甚至是无条件的:“警告:此实现不会打扰输出诊断它的作者认为很愚蠢,除了这个“就足够了),每个人都可以继续生活。