考虑
volatile int volatile * volatile vip; // (1)
和
volatile int volatile * volatile vipa[10]; // (2)
这两行代码都会触发-Wduplicate-decl-specifier
(请参阅rev 236142和gcc7 release notes)。我想知道我是否可以从给定的代码中删除一些volatile
说明符而不改变代码的语义,并理解它背后的原因。
因此,以下问题:
一个。在(1)中,第1和第2个volatile
限定符都是指int
,因此在gcc术语中是“重复”吗? (我在这里看C99 6.7.3.4。)
湾在(2)中,其中一个volatile
限定符是指数组的类型,而不是int
或指针本身,因此C99 6.7.3.8包含:
如果数组类型的规范包含任何类型限定符,则元素类型是限定的,而不是数组类型。
或者(2)中的volatile
说明符只影响int
和pointer
类型,而不影响数组的类型?
C。如果b的答案是否定的,我如何声明C99 6.7.3.8中描述的volatile
数组类型?是https://en.cppreference.com/w/c/language/array描述的语法(引用如下)?
限定符 - const,restrict或volatile限定符的任意组合,仅在函数参数列表中允许;这限定了此数组参数转换到的指针类型
让我们考虑一个关于C99的问题。如果C11在这方面有任何差异,请记下。
TL; DR:
- 在(1)中,第1和第2个
volatile
限定符都是指int
,因此在gcc术语中是“重复”吗? (我在这里看C99 6.7.3.4。)
是的,他们都有资格int
,他们是副本。
- 在(2)中,其中一个volatile限定符是指数组的类型,
not
是int还是指针本身,因此C99 6.7.3.8包含:
C99 6.7.3.8不在此处。限定符已经应用于元素类型。可以将限定符应用于具有typedef的数组,但也可以限定元素类型(参见下文)
C。如果b的答案是否定的,我如何声明C99 6.7.3.8中描述的易失性数组类型?
以typedef
为例。
C标准明确允许限定符不止一次出现。 C11 n1570 6.7.3p5:
如果同一个限定符在同一个specifier-qualifier-list中出现多次,或者直接或通过一个或多个typedef,则行为与它只出现一次相同。
即什么-Wduplicate-decl-specifier
不是这样的错误,但这样的代码逐字是可疑的 - 如果volatile int *volatile
错误拼写volatile int volatile *
导致指针不合格...
限定符适用于限定符左侧的类型,除非限定符本身是最左边的类型,在这种情况下它就好像它是基类型的右边,即
volatile int *
和
int volatile *
意思是一样的。因此在volatile int volatile
你可以删除其中一个。因此,你需要的是
volatile int *volatile vipa[10];
意思是vipais an array of 10
volatile-qualified pointers to
volatileint`s。
C99 6.7.3p8 / C11 6.7.3p9的含义是数组本身不能是易失性的 - 它的地址是常量,只有它的元素才能被限定。因此,如果数组类型是合格的,它只适用于其元素。如果typedef合格,情况就是如此:
typedef int intarray[5];
const intarray myarray;
将宣布myarray
仿佛
const int myarray[5];
而如果你使用typedef作为指针:
typedef int *intptr;
const intptr myptr;
这个限定符不会影响指向类型,但相当于
int *const myptr;
虽然volatile int
和int volatile
都是严格允许的,但C标准更喜欢前者。 C11 n1570 6.7.6.1p3:
- 示例下面的一对声明演示了''指向常量值的变量指针''和''指向变量值的常量指针''之间的区别。
const int *ptr_to_constant; int *const constant_ptr;
ptr_to_constant
指向的任何对象的内容不应通过该指针修改,但ptr_to_constant
本身可能会更改为指向另一个对象。同样,int
指向的constant_ptr
的内容可能会被修改,但constant_ptr
本身应始终指向同一位置。
还可以在括号内为数组添加类型限定符,但只能在函数参数中添加,因此您可以编写
void foo(int array[volatile])
这意味着几乎相同,参数衰减到一个合格的指针
void foo(int *volatile array)
但是你只能使用前一种风格的static
说明符。
解释很简单。
volatile int *
== int volatile *
在这种情况下,顺序无关紧要。
所以volatile int * volatile x;
== int volatile * volatile x;
如果你有volatile int volatile *
你已经宣布它是不稳定的,那么第二个就不需要了