1

对于嵌入式软件项目,我们需要使用一些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);

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

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

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

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

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

4

3 回答 3

3

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

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

于 2012-12-07T12:46:52.087 回答
1

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

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

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

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

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

于 2012-12-07T14:03:29.400 回答
0

这取决于由于volatile-ness而真正发生的事情。

如果这个数组中的值在函数执行过程中发生了变化,并且应该注意到这些变化,就让它成为volatile.

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

于 2012-12-07T12:27:05.553 回答