【问题标题】:How do I declare a static array with volatile elements?如何声明具有 volatile 元素的静态数组?
【发布时间】:2018-06-27 09:45:00
【问题描述】:

关于所用术语的说明:

对于静态数组,我的意思是静态分配的数组内存,例如:int x[10]。

问题

我需要声明一个带有易失元素的静态数组。 如果我很好理解 volatile 限定符的工作原理,它应该是:

volatile uint8_t *x; // x is a pointer to volatile uint8_t
uint8_t *volatile x; // x is a volatile pointer to uint8_t
volatile uint8_t *volatile x; // x is a volatile pointer to volatile uint8_t 

好的,但现在我需要对 静态数组 做同样的事情。 我试过了:

volatile uint8_t x[10];  // Only the pointer is decleared as volatile
uint8_t volatile x[10];  // Same as above
volatile uint8_t *x3[10]; // Casting problems and errors when I do ...  
*x3[0] = 1; // ... something like this. Moreover, I do not know if this...
            // ... statement declares the uint8_t element as volatile

谢谢!

更新

好的,正如我应该使用的 cmets 中突出显示的那样:

volatile uint8_t x[10]

据我所知,问题不在于声明,而在于我的代码中此变量的使用。我将此元素传递给原型为:

static void functionName(uint8_t *buffer, uint32_t size);

我是这样调用函数的:

functionName(x, 10);

编译器报告:传递 'functionName' 的参数 1 会丢弃指针目标类型中的 'volatile' 限定符

无法更改函数原型,如何解决?

【问题讨论】:

  • 首先,数组是不是指针。数组可以衰减为指向其第一个元素的指针,但它本身不是指针。其次,声明 volatile uint8_t x[10];x 声明为由 10 个 volatile uint8_t 元素组成的数组。
  • 我建议您通过 typedef 来“澄清”您的想法,您可以在其中定义数据类型 'volatile uint8_t *'
  • 如果您在传递函数参数时遇到问题,您可以更新您的问题以包含函数原型和错误消息。
  • 如果不能更改原型,就不可能告诉functionName 对象是易失的。您可以复制要传递给functionName 的数据并将其传递。例如,分配一些内存或声明一个本地数组,将数据从x 复制到该内存中,然后将该内存传递给functionName。当然,那么functionName 将不会看到在执行functionName 期间发生的对x 的任何更改。您基本上将拥有x 的非易失性快照。如果functionName 更改了数据,则在完成后将临时数据复制回x
  • 要么你需要一个 volatile 数组,要么你不需要。你不能有一个“有时不稳定”或“稍微不稳定”的数组。如果你需要一个 volatile 数组,将它传递给一个没有 volatile 限定的函数是一个错误,因为这样做没有任何意义。

标签: c arrays volatile


【解决方案1】:

声明一个包含 10 个 uint8_t 类型的 volatile 元素的静态数组只需:

volatile uint8_t x[10];

请注意,这是一个数组的声明,在这一步中,它与指针无关。

注意:稍后在您的代码中,如果您使用 x,它可能会衰减为指向第一个 volatile 元素的指针,但在这种情况下,该指针将具有一个常量值,在链接步骤中给出。指向的值显然是不稳定的。

【讨论】:

  • 实际上,当我使用:volatile uint8_t x[10] 时,编译器报告传递 'functionName' 的参数 1 会丢弃指针目标类型中的 'volatile' 限定符,其中参数 1 是 x。因此,它似乎是要声明为 volatile 的 [指向第一个元素的] 指针。
  • @igol 您还必须将volatile 添加到函数的参数列表中。否则函数无法知道它不能优化对该内存位置的访问。
  • @igol 我同意格哈德的观点。如果调用函数functionName(x),那么函数的原型必须像void functionName(volatile uint8_t* ptr),这样x指向的数据在函数代码中被认为是volatile。
【解决方案2】:

今天自己偶然发现了这个问题。 变量可能“有时”是易变的。 易失性意味着它的值可以在程序流程之外改变。通过并行线程或 ISR。 现在,如果 ISR 是“意外”更改值的原因,则它不会在 ISR 本身内部意外更改。因此,对于 ISR,该变量不是易失的,禁用编译器优化会适得其反。 如果我从 ISR 内部(并且仅从那里)调用函数,则该变量不是易失性的,我不想将指针传递给易失性,因为它会产生低效的代码。

对于这种情况,我找到的解决方案是有两个声明:

int a[x] = {};
volatile int * b = a;

现在外部世界使用 b(在头文件中全局声明)并将 b 指向的值视为 volatile,而 ISR(本地)定义两者并使用 a,将值视为非 volatile。

嗯,这是一个非常特殊的情况。一般来说,一个函数只看到函数参数声明。哪个是 volatile 或不是 volatile,因此函数将始终将参数视为 volatile 或始终视为不是。它不能根据传递参数的原始 volatile 限定符状态在两个可能完全不同的编译代码块之间自动切换。因此发出警告。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多