约束条件是否仅限于标题为“Constraints”的部分中的所有内容?
根据n1570 3.8(对程序施加的限制,要求符合规范的实现在违反时发出编译时诊断消息),我认为是的。
那些不在那些部分之外声明的每个要求都不是约束条件吗?
根据3.8的意义,我认为是的,但有一个更为循环的原因:标准的结构相当正式。只要适用,似乎就有明确的“约束条件”部分。因此,我理解在定义上,任何不在“约束条件”部分中的东西,在3.8的意义上都不是约束条件。除了“Constraints”部分外,还有一些“shall”条款完全可以在编译时执行,下面列举了一些示例。它们通常位于相邻的“Semantics”部分中。我可能会忽略某些细微差别,以防止在一般情况下进行编译时检测(因此不能强制进行诊断),或者可能标准不完全一致。但是,我认为编译器可以简单地翻译一个违反的程序,因为要求不在“Constraints”部分中。
标准中是否有关于“约束条件”的综合描述?
我认为只有3.8。我尝试在下面探索这个术语,并且同意该定义令人不满意。
术语“constraint”
让我们从基础知识开始。你引用的3.8中关于“约束”(constraint)的定义令人惊讶地难以理解,至少在没有上下文的情况下(“语法或语义上的限制,通过该限制可以解释语言元素的表述方式”)。“Restriction”和“constraint”是同义词,因此改写并没有增加太多内容;而“exposition of language elements”指的是什么呢?Exposition是一个有几个意思的单词;让我们从Dictionary.com中摘取,“主要用于传达信息的书写或演讲”,并假设它们是指标准的标准。那么,这基本上意味着此标准中的“约束”是对此标准中所说内容的约束。哇,我想不到。
Constraints按照3.8的定义
实际上,只需检查标准中实际的约束部分,就可以看到它们列出了强加给符合要求的程序的编译时限制。这是有道理的,因为只有编译时约束可以在编译时进行检查。这些附加限制是不能用C语法表达的。1
Constraints部分之外的限制
在约束部分之外的“shall”大多数用法对符合规范的实现强加限制。例如:“所有具有静态存储期的对象在程序启动之前必须初始化(设置为它们的初始值)”,这是符合实现的任务。
虽然在约束部分之外,还有一些“shall”条款对程序(而不是实现)强加了限制。我认为其中大多数属于3.18中提到的“调用库函数时对程序运行时的约束……”。它们似乎是运行时约束,无法在编译时通常被检测出来(因此诊断可能不是强制性的)。
以下是一些例子。
在6.5/7中,n1570详细描述了备受争议的别名规则:
一个对象的存储值只能由具有以下类型之一的lvalue表达式访问:
- 与对象的有效类型兼容的类型
- 与对象的有效类型兼容的已限定版本的类型,[...]
在6.5.16.1中,“简单赋值”:
如果在存储第一个对象的存储器的任何位置重叠读取另一个对象中存储的值,则重叠必须是精确的[...]。
其他示例涉及指针算术(6.5.6/8)。
“应该”子句可以在“约束”部分中
但是还有其他违反应在编译时检测到的shall语句,如果它们出现在相应的约束部分中,我不会感到惊讶。
- 6.6/6,“整数常量表达式中的强制类型转换运算符只能将算术类型转换为整数类型”(在“语义”下);如果无法检测常量和强制类型转换的类型,那么您可以在编译时检测到什么?
- 6.7/7,“如果标识符用于声明没有关联的对象,则该对象的类型必须在其声明符的结尾处完成”(在“语义”下)。对我而言,在代码某个时刻检测出类型是否完整似乎是基本的编译器任务。但是,我从未编写过C编译器。
还有更多示例,但正如我所说,我认为实现不需要诊断违规行为。成功通过编译器的违规程序只会公开未定义的行为。
1 例如,我理解语法不涉及类型 - 它只有通用的“表达式”。因此,每个运算符都有一个 约束 部分,详细说明其参数可接受的类型。例如移位运算符: “每个操作数应具有整数类型。” 尝试将浮点数的位进行移位的程序违反了这个约束,实现必须发出诊断。