为什么声明 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
指向某个硬件计数器寄存器,每次读取时该寄存器都会递增。所以假设它的初始值为 0
,foo(x)
调用将 return 0
并且计数器的值将是 1
。 bar(x)
将 return 1
并且计数器的值将是 2
。
volatile
于 1989 年在 ANSI C 中与 const
同时标准化,并按照相同的规则与类型限定符归为同一类别。
如果你有
void function(char *ptr);
然后出于显而易见的原因,如果您传入 const char
对象的地址,则会出现诊断:
{ const char c = 'A'; function(&c); } /* diagnostic required */
从形式上讲,这是如何工作的,即指向更合格类型的指针不能隐式转换为指向更不合格类型的指针。
由于 volatile
与 const
属于同一词汇类别(它是一个限定词),所以它的处理方式相同。
此外,如果通过不带有 volatile
限定符的左值访问定义了 volatile
的对象,则行为未定义。 (请注意,这是一个比 const
更宽松的要求区域:const
对象可以通过非 const-lvalue 访问;只有修改是未定义的。)我认为这是添加到语言中以证明处理的合理性volatile 概念作为类似于 const
的限定符;它实际上并没有多大意义。只是 "the way it is".
我正在尝试使用 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
指向某个硬件计数器寄存器,每次读取时该寄存器都会递增。所以假设它的初始值为 0
,foo(x)
调用将 return 0
并且计数器的值将是 1
。 bar(x)
将 return 1
并且计数器的值将是 2
。
volatile
于 1989 年在 ANSI C 中与 const
同时标准化,并按照相同的规则与类型限定符归为同一类别。
如果你有
void function(char *ptr);
然后出于显而易见的原因,如果您传入 const char
对象的地址,则会出现诊断:
{ const char c = 'A'; function(&c); } /* diagnostic required */
从形式上讲,这是如何工作的,即指向更合格类型的指针不能隐式转换为指向更不合格类型的指针。
由于 volatile
与 const
属于同一词汇类别(它是一个限定词),所以它的处理方式相同。
此外,如果通过不带有 volatile
限定符的左值访问定义了 volatile
的对象,则行为未定义。 (请注意,这是一个比 const
更宽松的要求区域:const
对象可以通过非 const-lvalue 访问;只有修改是未定义的。)我认为这是添加到语言中以证明处理的合理性volatile 概念作为类似于 const
的限定符;它实际上并没有多大意义。只是 "the way it is".