我现在的问题是,如果我使用const
声明了一个常量,我读到可以在外部修改它(可能是通过连接到系统的设备)。我想知道是否可以检查我的常量是否已被修改。当然,我会尝试这样的事情:
const double PI = 3.1412 //blah blah blah
// ...
if (PI == 3.1412) {
// do something with PI
}
显然不会编译,因为常量不能是左值。
我该如何解决这个问题?或者这是不可能的(如果不能做的话,我不想浪费我的时间)?
感谢。
答案 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)
如果不调用未定义的行为,则无法更改常量变量。防范这一点毫无意义。