【问题标题】:Volatile keyword allows access to const structures in UnitTest++Volatile 关键字允许访问 UnitTest++ 中的 const 结构
【发布时间】:2012-02-23 12:45:06
【问题描述】:

我正在使用 UnitTest++ 框架对我负责的一些 C 代码实施单元测试。最终产品被嵌入并使用 const 结构来保存配置信息。由于目标主机可以异步修改配置,因此结构的成员都是易失的。一些结构也被声明为 volatile。

当我使用 const_cast 尝试修改 UnitTest Windows 7 主机上缺少 volatile 关键字的结构实例时,我遇到了分段错误。这对我来说很有意义。但是,如果结构实例是使用 volatile 关键字声明的,则测试通过。这对我来说没有意义。

这是一个快速的代码示例,显示了 Win7 上 gcc 的问题。切换定义值会导致段错误出现与否,具体取决于是否使用了结构体的 volatile 实例。

typedef struct
{
    volatile int foo;
    volatile int bar;
} TestStruct;

const TestStruct constStruct = { 1, 2};
volatile const TestStruct volatileConstStruct = { 3, 4};

#define SEG_FAULT 0

int main(void)
{
    TestStruct * constPtr = const_cast<TestStruct*>(&constStruct);
    TestStruct * constVolPtr = const_cast<TestStruct*>(&volatileConstStruct);

    #if(SEG_FAULT == 0)
        constVolPtr->foo = 10;
    #else
        constPtr->foo = 20;
    #endif
}

谁能帮我理解为什么 volatile 关键字提供了段错误的解决方法?另外,任何人都可以提出一种方法来允许我修改结构中的值以进行单元测试,而无需将 volatile 关键字添加到所有结构实例中?

编辑:

我刚刚发现你可以在 C 中做到这一点:

#define const

在测试夹具中包含上述有效的“const undefine”可以让我的目标编译器看到 const 关键字并将结构正确地放入闪存中。但是,UnitTest++ 编译器上的预处理器去掉了 const 关键字,所以我的测试夹具能够修改结构。

此解决方案的缺点是我无法添加单元测试来验证函数调用的正确 const 操作。但是,由于从结构实例中删除 const 不是一种选择(需要将数据放在闪存中),这似乎是我必须忍受的一个缺点。

【问题讨论】:

  • 您在代码级别混合 C 和 C++,而不仅仅是在接口级别,这可能是个坏主意。这是两种不同的语言。特别是他们对什么是常量和什么是const 限定对象的概念不同。
  • 我正在使用需要 C++ 模块的 UnitTest++ 来测试 C 代码。为了示例的目的,我将所有混合的 C/C++ 放入同一个文件中(我无法分享我正在处理的实际代码)。在我的环境中没有混合 C/C++。

标签: c++ c unit-testing constants unittest++


【解决方案1】:

为什么会出现这种奇怪的行为?
使用const_cast 修改const 对象是一种未定义行为
const_cast 用于当您有一个指向非 const 对象的 const 指针并且您想要将指针指向时给它。

为什么它适用于 volatile
不确定。然而,它仍然是一个未定义的行为,你很幸运它可以工作。

未定义行为的问题在于,所有安全赌注都已关闭,程序可能会显示任何行为。它可能看起来有效,也可能无效。可能会崩溃或显示任何奇怪的行为。
最好不要编写任何表现出未定义行为的代码,这样可以节省对此类情况的保证解释。

如何解决这个问题?
不要将你修改的对象声明为const,因为你打算在你的程序/测试过程中修改它们,它们不应该是const。目前,您正在向编译器承诺您的结构对象是不可变的(const),但后来您通过修改它来破坏该合同。只有在你能信守诺言的情况下才能做出这个承诺。

【讨论】:

  • 我宁愿说“const_cast 用于获取指向 const 对象的非常量指针”,因为这是典型的用例。 (例如,认为 C++ 的 strchr。)
  • C++ 有一个strchr 的常量重载来避免这种情况。
  • 谢谢,我没有意识到这是未定义的行为。如下所述,我正在使用嵌入式处理器。该结构使用 const 关键字放入闪存中。我只需要修改它来配置存储在结构中的模块参数来设置单元测试。我必须想出另一种解决方法,因为我不想依赖 volatile 关键字将存储推入可写内存的未定义行为。
  • 删除 const 关键字可能是大多数处理类似问题的人的最佳答案。但是, lindydancer 的回答胜过了您的回答,因为它帮助我理解了规范中的 volatile 关键字定义。感谢您的帮助!
【解决方案2】:

我相信标准中的一个脚注会给你答案。 (请注意,脚注不是规范性的。)

在标准草案 N1570 的 §6.7.3 中:

132) 实现可能会放置一个非易失的 const 对象 在只读存储区域中。

这意味着使用 volatile 关键字定义的结构将被放置在读写内存中,尽管它已定义为 const

有人可能会争辩说,不允许编译器将任何结构放置在只读内存中,因为它们都包含易失性成员。如果我是你,我会发送编译器错误报告。

谁能帮我理解为什么 volatile 关键字呈现 段错误的解决方法?另外,任何人都可以提出一种方法来 允许我修改结构中的值以进行单元测试,而无需 将 volatile 关键字添加到所有结构实例?

你不能。一个const 对象被放置在只读内存中,如果你写入它就会触发一个段错误。要么删除const,要么添加volatile——我强烈建议删除const

【讨论】:

  • 我的理解是const只是禁止代码直接修改数据。由于我正在研究微型计算机,因此 const 用于告诉编译器将数据放入闪存中。可以修改,但不能直接访问。
猜你喜欢
  • 1970-01-01
  • 2013-08-06
  • 2017-02-18
  • 1970-01-01
  • 2013-01-18
  • 2017-07-03
  • 1970-01-01
  • 2021-08-02
相关资源
最近更新 更多