为什么声明 unsigned char "Volatile" 会使其与 "non-volatile" unsigned char 不兼容?

Why does declaring an unsigned char "Volatile" make it incompatible with a "non-volatile" unsigned char?

我正在尝试使用 volatile unsigned char 作为函数的指针数组参数。我创建了函数:

static void queue_to_serial(unsigned char *queue)

我使用 "static" 作为函数,因为它只能在当前源文件中使用。然后我调用该函数并提供地址:

queue_to_serial(&queue);

我得到一个错误:

Error[Pe167]: argument of type "unsigned char volatile (*)[8]" is incompatible with parameter of 
type "unsigned char *"

该数组被声明为易变的,但据我所知,这意味着它不会被优化,因为它可以异步更改

static volatile unsigned char queue[MAX_NUM_CONNECTED_VALVES];  

数组也被声明为静态的,因为我想保留分配给变量的值。除非数组在函数为 运行 的确切时间更新,否则这在我看来应该是可行的,因为 volatile unsigned char 使用的内存与 unsigned char 相同。使变量易变如何改变它?还是将其声明为指针会导致它在不同位置占用内存?谢谢

当你写一个函数如

int foo(char* x);

编译器将为此函数生成一些代码,不会知道您要cast的参数类型到 char* 并传递给它。所以它会假设 x 是指向一些可以用通常方式优化的常规内存的指针,例如:

int foo(char* x) 
{
    a = x[0];
    b = x[0];
    return a + b;
}

可以优化为 return 2 * x[0]; 之类的东西 - 即从 x[0].

执行单次读取

现在考虑

int bar(volatile char* x) 
{
    a = x[0];
    b = x[0];
    return a + b;
}

这次编译器必须x生成两次读取。

为什么重要?认为 x 指向某个硬件计数器寄存器,每次读取时该寄存器都会递增。所以假设它的初始值为 0foo(x) 调用将 return 0 并且计数器的值将是 1bar(x) 将 return 1 并且计数器的值将是 2

volatile 于 1989 年在 ANSI C 中与 const 同时标准化,并按照相同的规则与类型限定符归为同一类别。

如果你有

void function(char *ptr);

然后出于显而易见的原因,如果您传入 const char 对象的地址,则会出现诊断:

{ const char c = 'A'; function(&c); } /* diagnostic required */

从形式上讲,这是如何工作的,即指向更合格类型的指针不能隐式转换为指向更不合格类型的指针。

由于 volatileconst 属于同一词汇类别(它是一个限定词),所以它的处理方式相同。

此外,如果通过不带有 volatile 限定符的左值访问定义了 volatile 的对象,则行为未定义。 (请注意,这是一个比 const 更宽松的要求区域:const 对象可以通过非 const-lvalue 访问;只有修改是未定义的。)我认为这是添加到语言中以证明处理的合理性volatile 概念作为类似于 const 的限定符;它实际上并没有多大意义。只是 "the way it is".