不明确使用(void)寄存器值

时间:2017-05-07 09:21:05

标签: c casting void

我有一些示例代码(来自Nordic),其中包括下一行:

    NRF_RADIO->EVENTS_END = 0;
    (void)NRF_RADIO->EVENTS_END;

NRF_RADIO-> EVENTS_END是一个嵌入式寄存器,在第一行设置为0.

有人可以解释第二行的含义吗?

由于 亚龙

2 个答案:

答案 0 :(得分:4)

第二行"仅#34;读回寄存器。它这样做,通过将(void)强制转换为void来明确忽略读取的实际值。

该专栏有两个专业,可能会使理解变得非常重要:

  1. 不使用该值读取,为什么?
  2. 除了不使用该值外,还明确表示会被忽略,为什么?
  3. 1的原因很可能是(根据OP声明)涉及外设寄存器的事实。这可能意味着需要看似无用的读取的机制。例如:

    • 芯片供应商只是要求,为了可靠,按时间顺序预测前一次写入访问的影响,必须进行虚拟读取;
      这有时(至少是我和我的同事)被描述为推荐的序列",即不是必要的直观陈述,制造商禁止观察以确保功能
    • 写访问具有可靠的效果,但为了确保其所需的时间顺序,与其他语句相比,从寄存器读回是必要的
      • 这通常伴随着" volatile"表示寄存器的声明中的关键字
      • 这可能是(单独的)推荐序列"这只是受年表影响的用例所必需的
      • 请注意两个连续的语句两个不同的特殊寄存器可以有不同的" fast"效果,以便第二个在第一个之前生效
      • 一个例子是第一次访问外围设备,如端口,通过慢速总线连接; 然后第二次访问更快连接的外围设备,例如内存映射中断控制器;
        在重新配置端口之前,不希望重新配置中断,可能需要按时间顺序排序。

    2的原因完全是分开的,例如可以是:

    • (可能特殊的,特定于硬件的)编译器为所有忽略的返回值发出警告;
      许多编译器这样做,因为忽略返回值通常是潜在的错误来源,或者可能表明程序员存在根本的误解
    • 在编译器之上,使用静态分析工具,它们具有相似的目标:检测任何东西,根据经验可能表明错误并通过编码样式提高可维护性

    编辑可读性和更好的结构,不改变基本逻辑;为了有希望防止误解,我认为这是两个贬低者。如果有合理的原因,请告知我们。

答案 1 :(得分:-1)

对于某些设备,读取寄存器可能会产生副作用。 例如,I / O内存:

  

I / O内存只是一个类似RAM的位置区域,设备通过总线提供给处理器。此存储器可用于多种用途,例如保存视频数据或以太​​网数据包,以及实现与I / O端口一样的设备寄存器(即,它们具有与读取和写入相关的副作用)。 / p>

以下行可能是为了激活此设备上的某种副作用:

(void)NRF_RADIO->EVENTS_END;

有时您只想从寄存器中读取数据,以使CPU等待写入数据。

然而只是在不使用数据的情况下读取数据可能会使编译器发出警告,如果使用优化,最终会完全删除此语句(如下所示)

解决方案(感谢以下评论编辑)

  • 向void添加强制转换声明编译器您知道自己在做什么,并且不会发出警告。
  • 为避免从程序中删除此语句,结构中的字段也应该是易失性的。

例如

为了演示如何在代码中添加/删除(void) / volatile可能会影响生成的代码,我将在此处展示一些示例。

注意:以下示例是C / C ++的未定义行为,但在gcc + x86下定义良好。

以下程序会产生警告,但运行它不会产生分段错误,因为永远不会读取指针(编译器会认为它是多余的)。

struct example {
    int b;
};

int main() {
   struct example * a = NULL;
   a->b;
   return 0; 
}

以下程序会产生警告,但运行因使用volatile而产生分段错误。虽然编译器知道这个位置需要直接使用,但是它不知道它可能有什么副作用。

struct example {
    volatile int b;
};

int main() {
   struct example * a = NULL;
   a->b;
   return 0; 
}

以下程序会产生任何警告,但运行 会产生分段错误。

struct example {
    volatile int b;
};

int main() {
   struct example * a = NULL;
   (void)a->b;
   return 0; 
}

以下程序会产生任何警告,并且运行 会产生分段错误。

struct example {
    int b;
};

int main() {
   struct example * a = NULL;
   (void)a->b;
   return 0; 
}