6.7.4.1 一般规定
IMPORTANT
这一节说的不是“限定符长什么样”,而是它们真正改变了哪些语义。const、volatile、restrict、_Atomic 的效果完全不同,不能混成一种“只读修饰”去理解。
类型限定符
- 类型限定符包括:
constrestrictvolatile_Atomic
约束
restrict只能用于:- 指向对象类型的指针类型;
- 或元素为此类指针类型的数组类型。
若实现不支持原子类型,就不能使用
_Atomic限定符。_Atomic修饰的类型不能是数组类型或函数类型。
语义
限定类型相关属性,只有在表达式是左值时才真正有意义。
同一限定符若在同一类型形成过程中重复出现,无论是直接写的,还是通过
typeof、typedef间接带来的,效果都与只出现一次相同。若
_Atomic与其他限定符一起出现,得到的是“同时带这些限定符的原子类型”。若通过一个非
const限定左值去修改一个以const限定类型定义的对象,行为未定义。若通过一个非
volatile限定左值去访问一个以volatile限定类型定义的对象,行为未定义。volatile对象可能以实现未知的方式被改变,因此对它的访问必须严格遵守抽象机规则,不能随意优化掉或重排。什么算对
volatile对象的一次访问,由实现定义。通过
restrict限定指针访问的对象,会与该指针建立一种特殊关联;这套形式化规则在6.7.4.2里定义。标准明确指出:
restrict的设计目的主要是帮助优化。对一个合格程序,如果完全删掉所有restrict,它的可观察行为本应不变;唯一显著例外是程序自己用_Generic去区分是否带该限定符。若数组类型说明中含有限定符,那么数组类型与元素类型都视为带该限定。
若函数类型说明中含有限定符,则行为未定义。
两个限定类型要兼容,必须是“以相同限定方式修饰的兼容类型”;限定符书写顺序不影响类型。
例子
- 下面这个对象可以被硬件修改,但不能直接赋值、自增或自减:
extern const volatile int real_time_clock;- 聚合类型会把限定传播到成员可见的类型效果上。例如:
const struct s { int mem; } cs = { 1 };这里 cs.mem 不能通过 int * 去修改。
- 声明:
_Atomic volatile int *p;表示 p 的类型是“指向 volatile atomic int 的指针”,而不是“原子指针”。