【问题标题】:Reason for volatile nonstatic local variable in CC中易失性非静态局部变量的原因
【发布时间】:2020-07-15 13:42:52
【问题描述】:

参考以下代码:

void calledFunction(volatile uint8_t **inPtr);
volatile uint8_t buffer[] = {0,0,0,0,0,0}; 

volatile uint8_t *headPtr = buffer;

void foo(void)
{
    volatile uint8_t *tmpPtr = NULL;

    tmpPtr = headPtr;

    //This function modifies tmpPtr
    calledFunction(&tmpPtr);

    headPtr = tmpPtr;
    return;
}

这是我试图使中断安全的代码的简化版本,我不确定为什么这个本地被定义为volatile。我知道没有性能原因(即保证此函数至少为 O(n)),因为此函数应该尽可能高效地运行。

这个函数可以在主执行和内部中断中调用,但是由于tmpPtr是一个非静态局部变量,它应该不能被foo()的任何其他实例修改。

在这种情况下,我看不到任何需要 volatile 关键字的访问模式。

简而言之,函数foo()tmpPtrvolatile关键字的作用是什么?

编辑:在函数参数中忘记了&

EDIT2:我继承了这段代码,需要修改它。 我的主要问题是volatile 关键字在这种情况下是否有任何特殊的有效理由。

EDIT3:添加了calledFunction()的原型

EDIT4:在原始代码中添加了重要说明,headPtrbuffer 都具有 volatile

【问题讨论】:

  • 它不是volatile,它是一个指向volatile的指针。它指向全局buffer。因此,如果从中断上下文调用foo,您需要确保它实际上可以访问buffer
  • 另外,您通过 value 传递 tmpPtr,因此 calledFunction 不会(也不能)修改它。
  • @AdrianMole 这是一个指针。该函数可以修改指针。但是,是的,在那之后的那句话让我怀疑意图
  • @EugeneSh。是的,但是代码注释说“modifes tmpPtr”——它不能这样做。只能修改*tmpPtr
  • @AdrianMole 是的,下一行可能暗示你是对的。

标签: c embedded volatile


【解决方案1】:

tmpPtrvolatile 的原因是因为tmpPtr 需要引用volatile uint8_t,而不是因为tmpPtr 本身就是volatile(它不是)。

正如@Eugene Sh. 最初指出的那样,这个问题是由于在定义volatile 指针和变量时对语法的误解而出现的。 This question 对指向 volatilevolatile 指针的指针的语法有很好的解释。

【讨论】:

    【解决方案2】:

    Volatile 限制编译器在访问(读取或写入)此指针指向的数据时进行优化。

    这经常出现在嵌入式或中断中,因为内存映射外设无法优化通常“无关”的读取或写入。

    例如,

    int32_t variable = 0;
    variable = 1;
    variable = 2;
    variable = 3;
    

    优化编译器会跳过将变量的值设置为 0、1 和 2,而只是将其设置为 3。通常这很好,但如果我们不是写入普通变量,而是写入内存映射端口,我们实际上希望每个写入都发生。

    这甚至可能发生在硬件接口之外。如果一个单独的线程在循环中寻找要设置为 2 的变量,优化编译器会阻止这种情况发生。

    它是本地的这一事实并不重要。只是 volatile 的大多数用例都是使用翻译单元(或使用 extern 的交叉翻译单元)范围实现的。

    两个例子是内存映射寄存器定义(结构通常是全局的,通常在头文件中,通常指向结构的指针的实例是全局的,尽管它不是必须的),以及像我们的标志线程示例。

    我不提倡任何一种设计,但您会在嵌入式开发中经常遇到它。

    【讨论】:

    • 感谢您的详细回复。我了解volatile 在嵌入式开发环境中的含义。之所以问我的主要问题,是因为我对将变量声明为指向 volatile 与 volatile 指针的语法有误解。我将tmpPtr 的声明读为易失性指针,而不是指向易失性的指针(它是)。将 tmpPtr 视为 volatile 指针对我来说毫无意义,因为它是在本地声明的(而不是静态的)
    • 它是本地的还是非静态的这一事实仍然无关紧要。你可以设计一个像上面的 foo() 的例子,但是有一个 volatile 指针 (uint8_t * volatile tmpPtr),它在 calledFunction() 中被间接修改(例如,消息队列到另一个线程)和一个 while 循环等待在 foo() 底部更改的指针。查看stackoverflow.com/questions/9935190/…
    • 我工作过的一家商店总是在类型右侧有限定符以使事情保持一致,这让我的生活变得更加轻松。例如:int32_t const * const 变量; -- 第一个 const 指的是 int32_t,第二个 const 指的是指针。 volatile 也可以这样做。例如:uint32_t volatile const * volatile const variablePointer。不过,我保证这会让你在同事中非常不受欢迎。
    猜你喜欢
    • 2012-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多