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

Checking if my const variable has not been modified externally

本文关键字:外部 修改 是否 我的 const 变量 检查      更新时间:2023-10-16

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

const double PI = 3.1412 //blah blah blah
// ...
if (PI == 3.1412) {
// do something with PI
}

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

我该怎么做?还是不可能(如果做不到,我不想浪费时间(?

谢谢。

首先,为什么你的示例不编译? 如果你不能比较常量,它们就有点没用了。

我会将其归类为浪费时间。 如果程序外部的东西正在修改你的内存,那么有什么可以阻止它修改你存储比较的内存呢? 在您的示例中,该测试可能失败不是因为PI更改了,而是因为3.1415更改了...毕竟,这个数字存储在某个地方。

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

无论哪种情况,编译器都可能会认为测试是浪费时间,并将其全部删除。


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

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改变了,断言将失败。

常量折叠在这里很重要。使用示例代码,

const double PI = 3.1412; //blah blah blah
if (PI == 3.1412) {
}

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


您似乎想要某种"保险"或"篡改检测"。

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

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

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

所有这些都引出了一个问题:你需要这种安全性做什么。根据答案,实施上述内容以及更多内容甚至可能是合理的。

$0.02

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

我相信

,一旦你通过一些优化编译你的代码,编译器就会发出带有常量文字(如3.1412(而不是变量名(如PI(的机器代码。因此,机器代码很可能没有您在代码中使用的符号(即PI(。

static const double PI = 3.14;

防止从使用此常量编译的其他模块修改此常量。OTOH,它不会避免使用十六进制编辑器或内存中更改此常量。

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

#define PI 3.14

而且,是的,您可以使用

M_PI

不断。看到这个问题

我假设必须修改 const 所在的实际内存空间才能修改。除非您有明确的理由/问题进行此类检查,否则我会说这不是必需的。我从来不知道有什么需要检查常量的值。

如果你有一个声明的非易失性const变量,就没有合法的方式可以在外部修改它。

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

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

如果不调用未定义的行为,就无法更改常量变量。对此进行辩护是没有意义的。