【问题标题】:pointers in a volatile struct in CC 中 volatile 结构中的指针
【发布时间】:2016-06-22 14:39:43
【问题描述】:

假设我有一个结构

typedef struct A{

int a1;
int *a2;

}A_t;

现在如果我声明这个结构的一个实例是 volatile -

volatile A_t trial;

我使用 volatile 指针来访问这个 volatile 结构。

volatile A_t *ptrToTrial = &trial;

如果我尝试这样做:

int *ptrToField = ptrToTrial->a2;

ptrToField 也应该是易变的吗?编译器是否会知道 prtToField 是 volatile 而没有明确提及,因为它是通过 volatile 的 ptrToTrial 访问的?

还有如果有函数的话-

function trialFunction(A_t *trialptr)
{
     int *p = trialptr->a2;

}

如果我们用上面声明的 volatile ptr 调用这个函数 -

trailFunction(ptrToTrial)

我收到一个错误:volatile A_t* is incompatible with parameter of type A_t

因此,如果我将函数定义更改为包含volatile,我不会看到错误。

function trialFunction(volatile A_t *trialptr)
{
     int *p = trialptr->a2;

}

编译器不应该也抱怨指针p - 因为p 是非易失性的而trialptr->a2 是易失性的吗?

【问题讨论】:

  • 您的代码并不清楚您如何使用volatile。但请注意,它并没有像许多人认为的那样做。其实it's all but useless in actuality.
  • 只有在类型说明符中明确声明为volatile 的东西才会是易变的。在上述情况下,trial*ptrToTrial 是易失的。 ptrToTrial->a2 是 volatile 的,因为它是 volatile 结构的成员。但是ptrToTrial->a2[0]ptrToField[0](假设它们是有效的)不是易失性的。
  • "我使用一个 volatile 指针来访问这个 volatile 结构。" volatile A_t *ptrToTrial = &trial; --> 不,ptrToTrial 不是volatile,它指向的是volatile

标签: c pointers struct


【解决方案1】:

ptrToField 也应该是 volatile 吗?

根据您对struct A 的定义,成员a2 所指向的东西不会被声明为volatilestruct A 的给定实例是volatile 意味着它的成员a2(指针)是volatile,但不是它指向的东西是volatile。这就是int * volatile(相当于实际案例)和volatile int *的区别。

你描述的初始化...

int *ptrToField = ptrToTrial->a2;

... 用 pointer ptrToTrial->a2 的值初始化 ptrToField。因为ptrToTrial 指向volatile 对象,所以程序必须从主存储器加载指针(该易失性对象的成员)。因为指向的东西不是(声明为)易变的,但是,将ptrToField 的目标类型声明为普通int 不会丢失任何信息,也没有(新的)风险。当然,将ptrToField 本身声明为 volatile 没有任何好处。

如果不清楚,请注意,变量ptrToField 的名称与您使用它的用途不一致。您没有将其初始化为指向struct 的成员;相反,您将其初始化为struct 成员的副本

编译器是否会知道 prtToField 是 volatile 而没有明确提及,因为它是通过易失性的 ptrToTrial 访问的?

不需要行使它可能拥有的任何此类知识,并且无论如何,这些知识的范围可能非常有限。它知道该变量是如何初始化的,但可能很难预测其值何时以及如何被修改。在任何情况下,变量声明类型未携带的任何信息都与程序的标准 C 语义无关。

编译器不应该也抱怨指针 p - 因为 p 是非易失性的,而 trialptr->a2 是易失性的吗?

不,因为尽管trialptr->a2 是易失性的,但读取其(在某个给定时间点)并将该值分配给另一个变量没有问题。对象值是位模式,它们既不是易失的也不是非易失的——这是它们存储的一个特征,通过访问它们的左值进行通信。

【讨论】:

  • 那么以这种方式定义一个 volatile 指针不是总是有意义的 - A_t volatile *ptrToTrial = &trial;而不是 volatile A_t *ptrToTrial = &trial ?
  • @Curious91、volatile int *int volatile * 拼写不同,但它们是等价的,就像 volatile intint volatile 是等价的一样。这与类型限定符 const 相同,这是出现此类问题的更常见上下文。
  • int volatile* 意味着 ptr 指向的内存可能会改变,而 volatile int* 意味着指针仍然指向同一个内存,但存储在该内存中的值可能会改变。它们如何等效?
  • @Curious91,你完全误会了。诸如volatile 之类的类型限定符可能出现在它们所应用的类型说明符之前或之后,因此volatile intint volatile 完全相同,volatile int *int volatile * 完全相同。 int volatile * 类型表示指向易失性int 的非易失性指针,就像volatile int * 一样。要使限定符应用于指针本身而不是指向对象,它必须位于 * 之后。
【解决方案2】:

请注意,struct A 中的 int *a2; 不是易失性的。 所以

int *ptrToField = ptrToTrial->a2;

ptrToField 不是volatile

trailFunction(ptrToTrial) 出错是因为函数trailFunction 需要A_t *trialptr,但是你传递了volatile A_t*,这显然是编译错误。

最后:

function trialFunction(volatile A_t *trialptr)
{
     int *p = trialptr->a2;
}

编译就OK了,因为a2的类型是int*

【讨论】:

    【解决方案3】:

    我的首选位置通常是在指针声明中。这样,编译器会将结构中的所有寄存器视为易失性,但可能具有所述结构的其他(例如基于 RAM 的影子)实例,它们不是易失性的,因为它们实际上不是硬件寄存器下面。

    因此我建议您使用:

    typedef volatile struct
    

    祝你有美好的一天

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-14
    • 1970-01-01
    • 2016-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多