Volatile关键字允许访问UnitTest++中的常量结构

Volatile keyword allows access to const structures in UnitTest++

本文关键字:UnitTest++ 常量 结构 访问 关键字 许访问 Volatile      更新时间:2023-10-16

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

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

下面是一个快速代码示例,显示了Win7上的gcc问题。切换define值会导致segfault出现与否,这取决于是否使用了结构的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关键字为segfault提供了一个变通方法吗?此外,有人能提出一种方法,允许我修改结构中的值进行单元测试,而不向所有结构实例添加volatile关键字吗?

编辑:

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

#define const

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

这个解决方案的缺点是,我不能添加单元测试来验证函数调用的正确const操作。然而,由于从结构实例中删除常量不是一个选项(需要将数据放在闪存中),这似乎是我不得不面对的一个缺点。

为什么会有这种奇怪的行为
使用const_cast修改const对象是一种未定义的行为
当你有一个指向非常量对象的const指针,并且你想把指针指向它时,就会使用const_cast

为什么它适用于volatile
不确定。然而,它仍然是一种未定义的行为,你只是幸运的是它有效。

Undefined Behavior的问题是,所有安全赌注都被取消,程序可能会显示任何行为。它可能看起来有效,也可能不起作用。可能会崩溃或表现出任何奇怪的行为
最好不要编写任何显示"未定义行为"的代码,这样可以为此类情况保存有保证的解释。

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

我相信标准中的脚注会给出答案。(注意脚注不规范。)

在标准草案N1570的§6.7.3中:

132)该实现可以放置不易失的const对象在只读存储区域中。

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

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

有人能帮我理解为什么volatile关键字显示segfault的解决方法?此外,有人能建议一种方法吗允许我修改结构中的值以进行单元测试将volatile关键字添加到所有结构实例?

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