【问题标题】:const volatile pointer function argumentconst volatile 指针函数参数
【发布时间】:2012-12-07 12:21:18
【问题描述】:

对于嵌入式软件项目,我们需要使用一些const volatile TYPE * 指针。现在我们有了一些计算函数,如下所示:

uint8 calc(const volatile uint8 *array, uint8 value) { ... }

在函数执行期间,两个变量的数据都没有变化。

调用代码如下:

const volatile uint8 *array = (const volatile uint8 *)0x00010111;
uint8 value = 8;

uint8 result = calc(array, value);

现在的问题是,如果我们设计没有可变参数的计算函数,会有什么不同:

uint8 calc(const uint8 *array, uint8 value) { ... }

对于调用,我们抛弃了 volatile:

uint8 result = calc((const uint8 *)array, value);

第二种解决方案的优点是更灵活:我们也可以将该函数用于非易失性变量。但是,如果我们抛弃 volatile 并且我们的编译器进行一些强大的优化,它会有什么不同吗?

【问题讨论】:

  • 可能不会有任何区别。
  • 可能不会有什么不同,但是编译器可以在后台做很多事情,唯一确定的方法是查看生成的机器代码。考虑强制转换的一种方法是你告诉编译器“我比你更了解”;在这种情况下你不需要。

标签: c constants volatile


【解决方案1】:

您始终可以使用带有非易失性参数的函数。只是函数中的代码处理给定的对象就好像它们是易失的(很可能在途中失去性能)。有点难以想象一个带有可变参数的函数(“因为它们可能会在没有通知的情况下改变”)可以做什么。在您编写时,在您的情况下,数据无论如何都不会改变,因此最灵活的解决方案是声明参数 const 并忘记 volatile。

请使用“uint8_t”而不是像 uint8 这样的本土类型名称 - 自 1996 年以来它就已成为标准!

【讨论】:

  • 当然,我只是懒得写了 ;) - 我的同事只担心编译器(用于 tricore)正在做一些奇怪的优化。
  • 由于这里没有做任何未定义的事情,所以不允许编译器做太奇怪的事情。所有从你鼻子里飞出来的恶魔都是你自己的代码;)。
  • 这个答案似乎写得好像函数参数是易失的,但函数是用非易失参数调用的。但是,问题询问如何将函数参数修改为非易失性,但使用易失性但强制转换为非易失性的参数调用它。
  • @EricPostpischil 是的,我只是想纠正 OP 对他初始函数行为的看法。他已经瞄准了更好的解决方案,因此无需明确重复这一点。
【解决方案2】:

有两种情况:函数直接操作硬件寄存器等。那么你必须在参数中有 volatile。或者该功能与硬件寄存器无关。那么它不应该有易失性。这两种情况之间没有中间立场。

此外,calc((const uint8_t*)array, value); 只是一个糟糕的,可能是错误的版本

const uint8_t* ptr = array;
calc(ptr, value);

前一种形式不好,因为函数参数的求值顺序是未指定的行为。编译器可能会选择先计算左操作数或右操作数,您无法知道或假设顺序。由于访问 volatile 是一种副作用,因此每次构建程序时,您的原始代码都会给出不同的结果。这在实时嵌入式系统中尤其成问题(并且可能很危险)。

因此,建议不要在表达式中访问 volatile 变量(参见 MISRA-C:2004 12.2)。

【讨论】:

  • 我不同意这里。表达式“array”的求值不构成对 volatile 对象的访问。如果您有对它们的相互访问顺序敏感的对象(硬件寄存器)(例如中断标志和确认标志),那么 volatile 也不会保存您的火腿 - 现代指令重新排序深层管道会破坏任何强加程序流的尝试标准定义的“假设的理想C机器”。刚刚在嵌入式 PowerPC 上对这些属性进行了代码审查。
  • @slartibartfast 您不正确,易失性对象在被复制到非易失性函数参数时被访问。另外,我的言论根本与多处理或线程安全无关,我不知道你从哪里得到的。它们与实时性能有关,因此在我的帖子中使用“实时”文本。
  • 我看不到在调用中访问 volatile 对象(“array”指向)的位置。另外,我也没有提到多线程或多处理。它是重新排序管道内的单个执行线程,它破坏了程序员(和标准)在使用“易失性”时的意图。而这样的问题如何只与实时编程有关,我无法理解。要么你得到正确的代码,要么你没有?
【解决方案3】:

这取决于volatile-ness 真正会发生什么。

如果这个数组中的值在函数执行过程中发生了变化,需要注意这些变化,就设为volatile

如果没关系,或者如果“旧”值更重要,请省略 volatile

【讨论】:

    猜你喜欢
    • 2023-03-20
    • 2012-04-11
    • 2018-09-02
    • 2020-01-03
    • 1970-01-01
    • 2020-08-12
    • 2012-03-15
    • 2011-06-20
    • 1970-01-01
    相关资源
    最近更新 更多