2

我正在使用 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 不是一种选择(需要将数据放在闪存中),这似乎是我必须忍受的一个缺点。

4

2 回答 2

4

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

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

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

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

于 2012-01-31T19:28:19.423 回答
0

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

在标准草案 N1570 的 §6.7.3 中:

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

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

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

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

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

于 2012-01-31T20:15:02.793 回答