易失性指针指向非易失性数据

时间:2018-04-10 12:35:41

标签: c pointers volatile

我理解声明

int *volatile ptr;

表示指针本身是易失性的

int a=10;
int *volatile ptr=&a;

现在正在更新ptra。它是否会导致在访问a时返回ptr的旧值等潜在问题?

在我的场景中澄清易失性指针的用例:

  1. 要从中断上下文传递到任务上下文,我正在通过 地址到循环队列(指针数组)将 可以从任务上下文访问。
  2. 此队列中的指针声明为volatile。
  3. 在队列中的索引x处,存在指向的指针y 变量a。
  4. 现在,如果我写一个新的指向队列的指针(示例指针z指向 变量b)在中断上下文中的索引x处。
  5. 当我在任务上下文中读取索引x时,因为队列被声明为 volatile,指针不会被优化。
  6. 我怀疑是因为指针指向的是非易失性的,编译器是否有可能针对索引x进行优化,并且在索引x处引用指针时,它将指向变量a而不是变量b

3 个答案:

答案 0 :(得分:2)

如果ptr和ptr指向的int都由不同的线程或硬件更新,则必须声明ptr如下:

int volatile * volatile ptr=&a;

或者:

volatile int * volatile ptr=&a;

正如@Lundin指出的那样,通常在嵌入式编程中,地址不会改变,所以这就足够了:

volatile int * ptr=&a;

或者:

int volatile * ptr=&a;

答案 1 :(得分:1)

int* volatile仅表示指针本身为volatile。指向的数据不是volatile限定的,这意味着以下场景可能会导致优化程序错误:

int a=10;
int* volatile ptr=&a;

int main()
{
  for(;;)
  {
    printf("%d\n", *ptr);
  }
}

void some_ISR (void)
{
  a = something;
}

编译器小心不要假设ptr在循环中的每一圈都没有指向同一个地址,但除此之外,可以自由地假设:" aha,在阅读{{1我仍然指着ptr。它还没有更新,我知道它是10"。从理论上讲,编译器可以自由地生成机器代码,例如伪:

a

如果编译器可以将先前的值保存在CPU寄存器等中,则这种优化可能有意义。假设它可以通过这种方式摆脱大量的printf开销,这将是一个主要的优化。

所以,这并不能保护您免受错误的优化。要实现这一点,请改用val = *ptr forever { ptr = (update it by reading from memory) if ptr != previous val =*ptr print val previous = ptr } 。或者,如果指针本身也可能发生变化,volatile int*

  

要从中断上下文传递到任务上下文,我将地址传递给循环队列(指针数组),这些队列将从任务上下文中访问。

只有当指针本身被中断改变为指向别处时才有意义。同样,它并不意味着将更新指向的数据。但是当你编写"这个队列中的指针被声明为volatile。",你很好,假设这意味着指针是volatile int* volatile不是 {{1 }}

与整个问题无关,您还需要防止共享变量的非原子访问。 volatile* type没有给出这一点。

答案 2 :(得分:0)

a通过volatile指针的任何使用都会使取消引用也变得不稳定(因为指针的值没有被缓存,所以必须完全取消引用)但是,更好的是制作两者都是不可缓存的,所以可能的实现方式是:

volatile int a;
volatile int * volatile ptr = &a;

请三思而后行,因为您尚未将a声明为volatile,如果您已完成此操作,则会收到警告:

pru.c

 #include <stdio.h>
 int main()
 {
    volatile int a;
    int * volatile ptr = &a;
 }

和输出

$ make pru
pru.c:5:17: warning: initializing 'int *volatile' with an expression of type 'volatile int *' discards qualifiers
      [-Wincompatible-pointer-types-discards-qualifiers]
    int * volatile ptr = &a;
                   ^     ~~
1 warning generated.
从警告中可以看出,丢弃的限定符引用了指向的值。如果ptr被声明为非volatile,则会发出相同的警告:

pru2.c

 #include <stdio.h>
 int main()
 {
    volatile int a;
    int * ptr = &a;
 }

$ make pru2
cc -O -pipe  pru.c  -o pru
pru.c:5:8: warning: initializing 'int *' with an expression of type 'volatile int *' discards qualifiers
      [-Wincompatible-pointer-types-discards-qualifiers]
        int * ptr = &a;
              ^     ~~
1 warning generated.