检查我的const变量是否未在外部修改

时间:2011-06-24 17:55:25

标签: c++ const

我现在的问题是,如果我使用const声明了一个常量,我读到可以在外部修改它(可能是通过连接到系统的设备)。我想知道是否可以检查我的常量是否已被修改。当然,我会尝试这样的事情:

const double PI = 3.1412 //blah blah blah

// ...

if (PI == 3.1412) {
// do something with PI
}

显然不会编译,因为常量不能是左值。

我该如何解决这个问题?或者这是不可能的(如果不能做的话,我不想浪费我的时间)?

感谢。

8 个答案:

答案 0 :(得分:4)

首先,为什么你的例子不会编译?如果你无法比较常数,那么它们就没用了。

我认为这是浪费时间。如果程序外部的某些内容正在修改你的内存,那么还有什么可以阻止它同时修改你存储比较的内存?在您的示例中,该测试可能失败,因为PI已更改,但因为3.1415确实...此数字存储在某处,毕竟。

如果您的程序更改了PI的值,那么它就会被破坏,并且无论如何都无法确定测试是否可靠。这是坚定的未定义的行为,所以任何事情都会发生。它很像测试引用参数是否引用null ...一个定义良好的程序不可能导致测试失败,如果它可以通过你无法确定程序是否处于运行状态,所以测试本身就是浪费时间。

在任何一种情况下,编译器都可能会认为测试是浪费时间,并将它们全部删除。


现在,有一种情况与您最初提到的情况略有不同,这可能是您的消息来源所指的内容。请考虑以下代码:

void external_function();
void internal_function(const int& i) {
    cout << i << "...";
    external_function();
    cout << i;
}

internal_function内,编译器不能假设两个输出都相同。 i可以是对实际上不是const的整数的引用,external_function可以更改它。这里的关键区别是i引用,而在原始问题中,PI是一个常量

int pi = 3;
void external_function() { pi = 4; }
void internal_function(const int&);

int main() {
    internal_function(pi);
}

这将导致3...4被打印。尽管i是一个常量引用,但编译器必须假设它可能会发生变化,因为它看不到的东西可能会改变它。

在这种情况下,这种测试在某些情况下可能会有用。

void internal_function(const int& i) {
    const int original_i = i; 
    cout << i << "...";
    external_function();
    cout << i << endl;
    if(i != original_i) cout << "lol wut?" << endl;
}

在这种情况下,测试很有用。保证original_i没有改变[如果有,请参阅本答复的前半部分],如果i已更改,则断言将失败。

答案 1 :(得分:2)

const折叠在这里很重要。使用示例代码

const double PI = 3.1412; //blah blah blah

if (PI == 3.1412) {

}

文字可能实际上共享常量的存储空间。


似乎你想要某种“保险”或“篡改检测”。

为此,您必须使用某种证书对二进制文件进行自签名。但是,通过充分的逆向工程,可以破坏签名的验证。

因此,您实际上需要一个受信任的内核函数来在执行之前验证二进制文件。开源内核似乎具有适当的同行评审和交叉检查的好处。该内核真的需要TPM硬件来协助。然后,您需要了解物理安全性(您必须信任硬件供应商和托管位置的物理安全性)。

此外,您需要NX内核功能(或类似Win32 DEP),以防止执行可写内存。相反,你需要对可执行段进行内核保护(无论如何,这通常都是这种情况,允许共享内存映射,IIRC)。

所有这些只是引出了一个问题:你需要什么样的安全保障。根据答案,实施上述内容甚至可能更合理。

$ 0.02

答案 2 :(得分:1)

const的要点是标识符是常量。如果有人使用const_cast或其他技巧来破坏你的常量,那么他们的程序将具有未定义的行为。我不会在实践中担心这一点。

答案 3 :(得分:1)

我相信,一旦你通过一些优化编译代码,编译器会使用常量 literal (例如3.1412)而不是变量名称(例如PI)。因此,机器代码很可能没有您在代码中使用的符号(即PI)。

答案 4 :(得分:0)

static const double PI = 3.14;

阻止从使用此编译器编译的其他模块修改此常量。 OTOH,使用HEX编辑器或内存中不会更改此常量。

另一种解决方案(不推荐但可能)是使用

#define PI 3.14

而且,是的,你可以使用

M_PI

恒定。见this question

答案 5 :(得分:0)

我认为必须修改const所在的实际内存空间才能对其进行修改。除非你有明确的理由/问题要做这样的检查,否则我会说这不是必需的。我从来不知道需要检查常数的值。

答案 6 :(得分:0)

如果您有一个声明的非易失性const变量,则没有合法的方法可以在外部进行修改。

写入const变量是未定义的行为。在另一个翻译单元中声明extern double PI;将声明与您声明的不同的变量,因为您的内部链接,这意味着它只能重新声明相同的翻译单位。

即使是声明相同的变量,行为也是未定义的(因为类型标识中的const / non-const不匹配)。

答案 7 :(得分:0)

如果不调用未定义的行为,则无法更改常量变量。防范这一点毫无意义。