这两种易变的限定词用法都是多余的吗?

时间:2019-04-22 11:38:04

标签: c syntax language-lawyer declaration volatile

考虑

volatile int volatile * volatile vip; // (1)

volatile int volatile * volatile vipa[10]; // (2)

两行代码都触发-Wduplicate-decl-specifier(请参见rev 236142gcc7 release notes)。我想知道是否可以在不更改代码语义的情况下从给定代码中删除一些volatile指定符,并且也了解其背后的原因。

因此,以下问题:

a 。在(1)中,第一个volatile和第二个int限定词是否都引用volatile,因此在gcc术语中是“重复的”? (我在这里查看的是C99 6.7.3.4。)

b 。在(2)中,int限定符之一是引用数组的类型,而不是volatile或指针本身,因此C99 6.7.3.8成立:

  

如果数组类型的规范包括任何类型限定符,则元素类型是合格的,而不是数组类型。

或者(2)中的int说明符仅影响pointervolatile类型,而不影响数组的类型吗?

c 。如果 b 的答案是否定的,如何声明C99 6.7.3.8中描述的{{1}}数组类型?是https://en.cppreference.com/w/c/language/array中描述的语法(引号后面)吗?

  

限定词-const,restrict或volatile限定词的任意组合,仅在函数参数列表中允许;这可以限定将数组参数转换为的指针类型

我们认为这是关于C99的问题。如果C11在这方面有任何差异,请进行记录。

2 个答案:

答案 0 :(得分:5)

TL; DR:

  
      
  • 在(1)中,第一个volatile和第二个int限定词是否都引用了int,因此在gcc术语中是“重复的”? (我在这里查看的是C99 6.7.3.4。)
  •   

是的,它们都符合not的条件,并且都是 副本。

  
      
  • 在(2)中,易失性限定词之一引用数组的类型,typedef引用int还是指针本身,以便C99 6.7.3.8保持:
  •   

C99 6.7.3.8 在这里成立。限定符已经适用于元素类型。可以将限定符应用于具有typedef的数组,但也可以限定元素类型(请参见下文)

  

c。如果b的答案是否定的,我如何声明C99 6.7.3.8中描述的易失性数组类型?

-Wduplicate-decl-specifier为例。


C标准明确允许限定符出现多次。 C11 n1570 6.7.3p5

  

如果同一限定符直接或通过一个或多个typedef在同一specifier-qualifier-list中多次出现,则其行为与仅出现一次相同。

volatile int *volatile本身并不是错误,但是这种逐字记录 是可疑的-应该是volatile int volatile *误写为volatile int * 导致指针不合格...


该限定词适用于该限定词的左侧 left 的类型,除非该限定词本身是最左侧的一种,在这种情况下,就好像它是基本类型的右侧,即

int volatile *

volatile int volatile

表示同一件事。因此,您可以在volatile int *volatile vipa[10]; 中删除其中之一。因此,您需要的是

is an array of 10

表示 vipa -qualified pointers to易失性易失性typedef int intarray[5]; const intarray myarray; int。


C99 6.7.3p8 / C11 6.7.3p9的含义是数组本身不能是易失的-其地址是恒定的,只有其元素可以被限定。因此,如果数组类型是合格的,则仅适用于其元素。即使typedef合格也是如此:

myarray

将声明const int myarray[5]; 就像是

typedef int *intptr;
const intptr myptr;

如果您将typedef用作指针:

int *const myptr;

此限定符不会影响指向类型,但等同于

volatile int

虽然严格允许int volatileconst int *ptr_to_constant; int *const constant_ptr; ,但C标准更喜欢前者。 C11 n1570 6.7.6.1p3

  
      
  1. 示例以下几对声明演示了“指向常量值的变量指针”和“指向变量值的常量指针”之间的区别。

    ptr_to_constant
         

    ptr_to_constant指向的任何对象的内容都不能通过该指针进行修改,但是int本身可以更改为指向另一个对象。类似地,constant_ptr指向的constant_ptr的内容可以被修改,但是void foo(int array[volatile]) 本身必须始终指向相同的位置。

  2.   

还可以在方括号内为 array 添加类型限定符,但只能在函数参数中添加,因此可以编写

void foo(int *volatile array)

这意味着几乎相同,并且参数会衰减为合格的指针

static

但是您只能将let filter = GMSAutocompleteFilter() filter.country = "uk|country:fr|country:us" 指示符与以前的样式一起使用。

答案 1 :(得分:4)

解释很简单。

volatile int * == int volatile *

在这种情况下顺序无关紧要。

所以volatile int * volatile x; == int volatile * volatile x;

如果您拥有volatile int volatile *,则已经将其声明为易失性,则不需要第二个