【问题标题】:What is the correct way to initialize C++ structures with unions?用联合初始化 C++ 结构的正确方法是什么?
【发布时间】:2020-09-29 06:34:21
【问题描述】:

MISRA-C++ 规则 8-5-2 要求使用正确的大括号初始化 C++ 结构。 我有一个带有联合的结构,但我找不到正确的大括号组合来满足这个规则。我不确定我的代码是错误的还是来自静态代码分析器工具的误报警告。

这是结构:

typedef struct XMC_VADC_RESULT_CONFIG
{
    union
    {
       struct
       {
          uint32_t                         : 16;
          uint32_t data_reduction_control  : 4;  /**< Configures the data reduction stages */
          uint32_t post_processing_mode    : 2;  /**< Result data processing mode. Uses @ref  XMC_VADC_DMM_t
                                                      For normal operation select
                                                      XMC_VADC_DMM_t::XMC_VADC_DMM_REDUCTION_MODE
                                                      and data_reduction_control as 0*/
          uint32_t                         : 2;
          uint32_t wait_for_read_mode      : 1;  /**< Allow the conversion only after previous results are read*/
          uint32_t part_of_fifo            : 2;  /**< Make the result register a part of Result FIFO? */
          uint32_t                         : 4;
          uint32_t event_gen_enable        : 1;  /**< Generates an event on availability of new result. */
       };
       uint32_t g_rcr;
    };
} XMC_VADC_RESULT_CONFIG_t;

这是我的初始化代码:

    const XMC_VADC_RESULT_CONFIG_t resultConfig = 
{
  {
    {
    .data_reduction_control     = 0U,                                                   // No Accumulation
    .post_processing_mode       = static_cast<uint32_t>(XMC_VADC_DMM_REDUCTION_MODE),
    .wait_for_read_mode         = 0U,                                                   // Disabled
    .part_of_fifo               = 0U,                                                   // No FIFO
    .event_gen_enable           = 0U                                                    // Disable Result event
    }
  }
};

我也试过移除一组牙套,但没有帮助。 大括号的正确数量是多少?

【问题讨论】:

  • 请注意,MISRA C++:2008 的第 9-5-1 条规定根本不应使用联合((必需)不应使用联合.");所以请注意,如果您想继续使用联合,则需要正式偏离此规则。
  • 是的,我已经看到了。我的问题是结构定义在微控制器制造商提供的库中。我必须使用这个库。在这种情况下,使用联合来访问整个寄存器或单个位也是有意义的。
  • 我认为 MISRA 禁止联合,因为在 C++ 中通过联合进行类型双关语通常是未定义的行为
  • @amanning 该库很可能假定非 MISRA C。不是 MISRA-C++。为什么必须使用 C++?它不是声明寄存器映射的合适语言。
  • 库是C,但是我们的应用是C++,所以初始化是C++。

标签: c++ misra


【解决方案1】:
  • 正确、合规的支架放置为const XMC_VADC_RESULT_CONFIG_t resultConfig = { 0u };
  • MISRA-C++ 需要 C++03,因此您不能使用其他任何东西。
  • 指定初始值设定项(.name 语法)是一种 C 语言,仅存在于 C99 及更高版本。它们在 MISRA-C:2004 中是不允许的,但在 MISRA-C:2012 中(有一些特殊规则)。在 C++ 中,它们最近才被引入,在一个 C++ 版本中,您不允许在符合 MISRA 的应用程序中使用。
  • union 类型双关语通常不允许在任何 MISRA 中使用,尤其是在未定义行为的 C++ 中。该规则的一些例外情况在 C 中存在,但在 C++ 中不存在。
  • 在任何关键应用程序中存在位域,无论是否是 MISRA,都是非常值得怀疑的做法,因为它们的标准化程度非常低。

总结:您不能在任何形式的 MISRA 应用程序中使用此代码。删除并集和位域,并用位运算符和位掩码替换它们。

【讨论】:

  • 是的,当您从 1998 年以来一直生活在岩石(或 QFP?)下并且从未写过单曲的马虎 MCU 芯片供应商交给您一个马虎的寄存器映射时,这是一个大问题,近20年的专业代码行。因此,为了严格遵守 MISRA,在大多数情况下,您必须推出自己的注册地图。我在这里写了一些关于如何做到这一点的建议:How to access a hardware register from firmware?
  • 如果你幸运的话,一些商业工具链可能有真正符合 MISRA 的库,但我个人还没有遇到过。
  • 我们的代码不必符合 MISRA,我们只需使用静态代码分析器中的 MISRA 设置来捕获尽可能多的错误。
  • @amanning 好的,恭喜你,你找到了。 C++ 不允许联合类型双关语(与 C 不同),因此您不能在 C++ 中使用此寄存器映射。
【解决方案2】:

C++ 没有designated initializers until C++20,所以你会放弃那些。

const XMC_VADC_RESULT_CONFIG_t resultConfig = 
{
  {
    {
      0U,                                                   // No Accumulation
      static_cast<uint32_t>(XMC_VADC_DMM_REDUCTION_MODE),
      0U,                                                   // Disabled
      0U,                                                   // No FIFO
      0U                                                    // Disable Result event
    }
  }
};

【讨论】:

  • 我们的 Clang 编译器设置为 C++14,但它接受指定的初始化程序,我觉得这非常好,因为它使阅读代码更容易,您无需添加即可查看正在初始化的内容任何 cmets。
猜你喜欢
  • 2011-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-15
  • 1970-01-01
  • 2019-02-20
  • 1970-01-01
相关资源
最近更新 更多