Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 挥发性有机污染物及其有害影响_C_Linux Kernel_Embedded_Embedded Linux - Fatal编程技术网

C 挥发性有机污染物及其有害影响

C 挥发性有机污染物及其有害影响,c,linux-kernel,embedded,embedded-linux,C,Linux Kernel,Embedded,Embedded Linux,我是一名嵌入式开发人员,在使用I/O端口时使用volatile关键字。但是我的项目经理建议使用volatile关键字是有害的,并且有很多缺点,但是我发现在大多数情况下volatile在嵌入式编程中是有用的,据我所知,volatile在内核代码中是有害的,因为代码的更改将变得不可预测。在嵌入式系统中使用volatile也有缺点吗 Volatile告诉编译器不要优化与Volatile变量有关的任何内容 为什么不应使用“volatile”类型类内核文档中的最佳文章 volatile是c语言中的一个关键

我是一名嵌入式开发人员,在使用I/O端口时使用volatile关键字。但是我的项目经理建议使用volatile关键字是有害的,并且有很多缺点,但是我发现在大多数情况下volatile在嵌入式编程中是有用的,据我所知,volatile在内核代码中是有害的,因为代码的更改将变得不可预测。在嵌入式系统中使用volatile也有缺点吗

Volatile告诉编译器不要优化与Volatile变量有关的任何内容

为什么不应使用“volatile”类型类内核文档中的最佳文章


volatile是c语言中的一个关键字,它告诉编译器不要对该变量进行任何类型的优化

volatile int temp;
for ( i=0 ;i <5 ; i++ )
{
    temp = 5;

}
让我举一个简单的例子:

int temp;
for ( i=0 ;i <5 ; i++ )
{
    temp = 5;

}
int-temp;

for(i=0;i
volatile
仅在限定对象可以异步更改时才有用。此类更改可能发生

  • 如果对象实际上是一个硬件IO寄存器或类似的,并且在程序外部发生了更改
  • 如果对象可能被信号处理程序更改
  • 如果在调用
    setjmp
    longjmp
在所有这些情况下,必须声明对象
volatile
,否则程序将无法正常工作。(您可能会注意到,不同线程之间共享的对象不在列表中。)


在所有其他情况下,您都不应该这样做,因为您可能会错过优化机会。另一方面,限定一个不属于上述几点的对象
volatile
,不会使您的代码不正确。

不,
volatile
不会有害。在任何情况下。永远都不会。没有可能的格式良好的代码段在对象中添加
volatile
(以及指向该对象的指针)后,这将中断然而,
volatile
通常被理解得很差。内核文档声明
volatile
被认为是有害的原因是人们一直在用它来中断内核线程之间的同步。特别是,他们使用
volatile
整数变量,就好像访问它们是g保证是原子的,但事实并非如此

volatile
也不是无用的,特别是如果你是裸机,你会需要它。但是,像其他任何工具一样,在使用它之前理解
volatile
的语义是很重要的

什么是易失性
在本标准中,访问
volatile
对象被视为一种副作用,其方式与通过
++
--
递增或递减的方式相同

(…)如果一个实际的实现可以推断出它的值没有被使用,并且没有产生需要的副作用(包括调用函数或访问易失性对象引起的副作用),那么它就不需要对表达式的一部分求值

不适用。编译器必须在每个序列点丢弃它认为知道的关于
volatile
变量值的所有信息。(与其他副作用一样,当访问
volatile
对象时,由序列点控制)

其效果主要是禁止某些优化

int i;

void foo(void) {
  i = 0;
  while(i == 0) {
    // do stuff that does not touch i
  }
}
编译器可以将其放入一个无限循环中,不再检查
i
,因为它可以推断
i
的值在循环中没有改变,因此
i==0
将永远不会为假。即使有另一个线程或中断处理程序可能发生改变,这仍然成立
i
。编译器不知道它们,也不关心它们。明确允许它不关心它们

将此与

int volatile i;

void foo(void) {
  i = 0;
  while(i == 0) { // Note: This is still broken, only a little less so.
    // do stuff that does not touch i
  }
}
现在,编译器必须假设
i
可以随时更改,并且不能进行此优化。当然,这意味着,如果处理中断处理程序和线程,
volatile
对象是同步所必需的。但是,它们不够。

什么是易变的 <> > <代码> Value不保证是原子访问。如果您习惯于嵌入编程,这应该是直观的。如果您愿意,考虑一下8位AVR MCU的以下代码:

uint32_t volatile i;

ISR(TIMER0_OVF_vect) {
  ++i;
}

void some_function_in_the_main_loop(void) {
  for(;;) {
    do_something_with(i); // This is thoroughly broken.
  }
}
此代码被破坏的原因是对
i
的访问不是原子性的——在8位MCU上不能是原子性的。例如,在这种简单的情况下,可能会发生以下情况:

  • i
    is
    0x0000ffff
  • do\u(i)
    即将被调用
  • i
    的两个高位字节被复制到该调用的参数槽中
  • 此时,计时器0溢出,主循环中断
  • ISR更改为
    i
    i
    的下两个字节溢出,现在是
    0
    i
    现在是
    0x00010000
  • 主循环继续,将
    i
    的下两个字节复制到参数槽中
  • do\u使用
    0
    作为参数调用带有
    0的东西
类似的事情也可能发生在个人电脑和其他平台上。如果有什么不同的话,它可能会有更多的机会以更复杂的架构失败

外卖 所以不,使用volatile也不错,而且你会(经常)必须在裸机代码中完成。然而,当你使用它时,你必须记住它不是一根魔杖,你仍然必须确保你不会被自己绊倒。在嵌入式代码中,通常有一种特定于平台的方法来处理原子性问题;例如,在AVR的情况下,通常的撬杆方法是可中断的持续时间,如

uint32_t x;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
  x = i;
}
do_something_with(x);
…其中
原子块
m
uint32_t x;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
  x = i;
}
do_something_with(x);
atomic_int i;

void foo(void) {
  atomic_store(&i, 0);
  while(atomic_load(&i) == 0) {
    // do stuff that does not touch i
  }
}