6.7.13.8.1 一般规定
IMPORTANT
unsequenced 与 reproducible 不是“优化建议”那么简单。它们是在向实现承诺:函数访问对象的方式满足一组可被重排、可被合并推理的严格条件。若承诺不成立却仍这样声明,行为未定义。
约束
标准函数类型属性只有两个名字:
unsequencedreproducible
这类属性只能附着到:
- 函数声明符;
- 或函数类型的类型说明符。
它们都不能带属性参数子句。
这类属性到底在描述什么
它们的目标,是把“函数如何访问对象”告诉翻译器,好让翻译器能推导某些函数调用是否可安全重排。
标准把这些性质拆成四个基础概念:
statelessindependenteffectlessidempotent
然后定义:
reproducible = effectless + idempotentunsequenced = stateless + effectless + idempotent + independent
四个基础性质
stateless指函数及其调用链中,任何静态存储期或线程存储期对象定义都必须是const且非volatile。independent指函数调用所观察到的外部对象值,不会因为调用时机或调用间彼此影响而改变;若访问是经由指针形参完成的,则必须能归因到唯一那个指针形参。effectless指函数调用期间发生的存储操作,不会对调用外部可观察状态产生“越界副作用”;若确有可观察修改,也必须能归因到唯一某个指针形参所基于的左值。idempotent指把同一求值紧接着执行第二次,不会改变结果值,也不会改变可观察执行状态。
重要边界
这些属性虽然语义上附着到函数类型,但它们不是函数原型的一部分。
因此,重声明或类型转换时丢掉这些属性,仍可能是兼容的。
反过来,如果某函数定义并不满足这些性质,却通过带该属性的函数声明或函数指针被访问,则行为未定义。
浮点环境、区域设置、输入输出流、外部文件、
errno等库态,也都被标准视作这里讨论的“对象”。
推荐实践
若可能,实现应在某函数声明了这类属性、但函数定义实际不满足相应性质时给出诊断。
标准还建议:若程序声明某函数具备
independent或effectless性质,则其指针形参最好同时使用restrict,这样语义表达更完整。