所有的约束都出现在标题为“约束”的部分中吗?
在 n1570 3.8 的意义上(对程序施加的限制,需要符合要求的实现在违反时发出编译时诊断消息),我认为是的。
在这些部分之外陈述的每个要求都不是约束吗?
在 3.8 的意义上,我认为是的,但出于更循环的原因:标准的结构相当正式。只要适用,似乎就有一个明确的 Constraints 部分。因此,我理解 根据定义 任何不在 Constraints 部分中的东西都不是 3.8 意义上的约束。
Constraints 部分之外有一些“shall”子句,它们看起来完全可以在编译时强制执行,参见。下面举几个例子。它们通常位于相邻的语义部分中。我可能会遗漏在一般情况下阻止编译时检测的细微之处(因此不能强制进行诊断),或者标准可能不完全一致。但我认为编译器可以简单地翻译违规程序,正是因为要求不在约束部分中。
我错过的标准中有没有对约束的全面描述?
我认为 3.8 就是你得到的全部。我尝试探索以下术语并同意该定义不令人满意。
我深入研究了标准以找出答案。这是我的研究。
术语约束
让我们从基础开始。您引用的 3.8 中“约束”的定义令人惊讶地难以理解,至少在没有上下文的情况下(“限制,句法或语义,通过它来解释语言元素的阐述”)。 “限制”和“约束”是同义词,因此重新措辞并没有增加太多; “语言元素的展示”是什么意思?说明是一个有多种含义的词;让我们以Dictionary.com 的“主要用于传达信息的写作或演讲”为例,假设它们的意思是标准。那么它基本上意味着该标准中的 约束 是对该标准中所说内容的约束。哇,我没想到。
约束 根据 3.8
只要检查标准中的实际约束部分,就会发现它们列出了对符合程序施加的编译时间限制。这是有道理的,因为只能在编译时检查编译时约束。
这些附加限制是那些不能用 C 语法表达的限制。1
约束部分之外的约束
约束部分之外的“应”的大多数用法对符合的实现施加限制。示例:“所有具有静态存储持续时间应初始化(设置为
初始值)在程序启动之前”,一个符合要求的实现的工作。
在 Constraints 部分之外,有一些“shall”子句对 program(不是实现)施加了限制。我认为大多数与 3.18 中提到的“调用库函数时程序上的运行时约束 [...]”属于同一类别。它们似乎是在编译时通常无法检测到的运行时限制(因此诊断不是强制性的)。
这里有几个例子。
在 6.5/7 n1570 中详细介绍了备受争议的别名规则:
一个对象只能访问其存储的值
通过具有以下之一的左值表达式
以下类型:
- 与对象的有效类型兼容的类型
- 类型兼容的合格版本
与对象的有效类型,
[...]
在 6.5.16.1 中,“简单赋值”:
如果存储在一个对象中的值是从另一个以任何方式重叠的对象中读取的
第一个对象的存储,那么重叠应该是精确的[..]。”
其他示例涉及指针算法 (6.5.6/8)。
Shall 子句可以在 Constraints 部分中
但是还有其他的 should 子句,它们的违反应该在编译时被检测到;如果它们出现在相应的约束部分,我不会眨眼。
- 6.6/6, "整数常量中的转换运算符
表达式只能将算术类型转换为整数类型”(在“语义”下);如果您无法检测常量和强制类型转换,您可以在编译时检测到什么?
- 6.7/7,“如果声明对象的标识符时没有链接,则对象的类型应在其声明符的末尾完成”(在“语义”下)。对我来说,这似乎是一项基本的编译器任务,用于检测代码中某个类型是否完整。当然,我从来没有写过 C 编译器。
还有几个例子。但正如我所说,我认为诊断违规行为不需要实现。设法偷偷溜过编译器的违规程序只会暴露未定义的行为。
1 例如,我知道语法不处理类型——它只有通用的“表达式”。因此,每个运算符都有一个 Constraints 部分,详细说明其参数的允许类型。移位运算符的示例:“每个操作数都应具有整数类型。” 尝试对浮点数进行移位的程序违反了此约束,实现必须发出诊断。子>