_Atomic类型限定符和类型说明符之间有区别吗?

时间:2014-10-20 10:06:17

标签: c

为什么标准会产生这种差异?

似乎两者都以相同的方式指定原子类型

3 个答案:

答案 0 :(得分:7)

原子类型说明符: - :)

Syntax:     _Atomic ( type-name );

你可以像这样声明一个原子整数:

        _Atomic(int) counter;

_Atomic关键字可以_Atomic(T)形式使用,其中T是一个类型,作为等同于_Atomic T的类型说明符。因此,_Atomic(T) x, y;声明x和y具有相同的类型,即使T是指针类型。这允许简单的C ++ 0x与仅C ++ _Atomic(T)宏定义兼容为原子。

如果实现不支持原子类型,则不应使用原子类型说明符。 原子类型说明符中的类型名称不应引用数组类型,函数类型,原子类型或限定类型。

与原子类型相关联的属性仅对作为左值的表达式有意义。

If the _Atomic keyword is immediately followed by a left parenthesis, it is interpreted as a type specifier (with a type name), not as a type qualifier.

原子类型限定符: - :)

        _Atomic volatile int *p;

It specifies that p has the type ‘‘pointer to volatile atomic int’’, a pointer to a volatile-qualified atomic type.

引用类型为对象类型的指针类型以外的类型不应受限制。 _Atomic限定符修改的类型不应是数组类型或函数类型。 与限定类型关联的属性仅对于左值的表达式有意义。

如果同一个限定符在同一个specifier-qualifier-list中出现多次,或者直接或通过一个或多个typedef出现,那么行为就像它只出现一次一样。如果其他限定符与说明符限定符列表中的_Atomic限定符一起出现,则结果类型是如此限定的原子类型。

单独使用关键字_Atomic作为类型限定符。只要进行适当的转换(包括通过强制转换操作符),允许实现放宽对相应非原子类型具有相同表示和对齐的要求。

答案 1 :(得分:5)

是。它们是有区别的。当它用作类型说明符时,标准将其限制为(6.7.2.4 p(3)):

  

原子类型说明符中的类型名称不应引用数组类型,函数类型,   原子类型或合格类型

例如

typedef int arr[5];  
arr用作限定符时,

_Atomic可以是类型名称,但如果_Atomic用作类型说明符,则不能用作类型名称(如{{1} }})

答案 2 :(得分:0)

经过多次尝试,我发现了为什么需要这样做:指针

假设您有:

int foo = 1;
int bar = 2;
int *p = &foo;

图片作为存储位置,前两个保存一个int,最后一个保存指向第一个int的指针。 _Atomic使得这些内存位置适合原子操作。

出于与您的程序有关的原因,您可能需要:

  • foo是原子的,因此您可以例如原子地更改 foo的值为2而不是1。
  • p是原子的,因此您可以例如原子地更改p指向的内容,并指向bar而不是foo。

在第一种情况下,要使foo成为原子原子是容易的,在阅读时没有歧义:

_Atomic int foo;
atomic_store_explicit(&foo , 2, memory_order_release); /* valid atomic op. */

但是现在,如果要编写:p,则希望使p原子化。

_Atomic int *p;

...那不是你想要的!

也就是说,如上所述,它是指向原子int的非原子指针。严格来说,不能保证此指针将正确对齐以能够对其执行原子操作(尽管您将很难迫使编译器将指针未对齐!)。这意味着,如果您设法使指针未对齐,则对其执行的原子操作将有机会失败。另一方面,您想要的是一个指向int的原子指针,它不是必需的原子。

所以你必须写:

int bar = 2;
_Atomic (int *) p;
atomic_store(&p , &bar); /* now valid atomic operation */

现在您有了原子指针!

请注意,对于使foo int原子化的非常简单的情况,您也可以编写这三个声明中的任何一个,最后一个使用stdatomic.h中定义的便捷typedef:

  

typedef _Atomic int atomic_int;

_Atomic int foo;
_Atomic (int) foo;
atomic_int foo;

我通过一个int以及指向和int的指针使它变得“易于理解” ,但是当您不得不处理时

_Atomic (struct foobar *) *q;

您现在将知道q本身不是原子指针,但它指向指向foobar结构的原子指针!

因此,演示:

#include <stdatomic.h>
void test()
{
    _Atomic int foo = 1;         /*   Atomic   */
    _Atomic int *pf = &foo;      /* Non Atomic */
    _Atomic int **ppf = &pf;     /* Non Atomic */
    int bar = 2;                 /* Non Atomic */
    _Atomic (int *) pb = &bar;   /*   Atomic   */
    _Atomic (int *) *ppb = &pb;  /* Non Atomic */

    int *res;

    res = atomic_load(ppf); /* Not OK, yields a warning */
    res = atomic_load(ppb); /* This is correct */
}
  

在“测试”功能中:

     

test.c:13:6:警告:来自不兼容指针类型[-Wincompatible-pointer-types]的分配

     

res = atomic_load(ppf);

实际上,第一个atomic_load尝试返回一个非原子指针指向一个int:指向的int是原子的,而不是指针。它也可能会失败,因为不能保证&pf(ppf的内容)对于原子操作是正确对齐的(尽管实际上是这样,您必须将pf转换为未对齐的int才能使其失败)。

第二个atomic_load可以正确使用原子指针,并将其返回到'res'。