究竟什么是危险的使用魔法试的价值观(例如0xDEADBEEF)为文本?
-
16-09-2019 - |
题
不用说,使用硬编制的文字指针是一场灾难:
int *i = 0xDEADBEEF;
// god knows if that location is available
然而,究竟什么是危险的,在使用六角文字作为可变 值?
int i = 0xDEADBEEF;
// what can go wrong?
如果这些数值的确是"危险的",由于他们的 用于各种调试方案, 然后这意味着,即使我做不使用这些文本的任何程序在运行期间发生偶然发现的一些数值可能会崩溃。
任何人解释的真正危险的使用六角文字?
编辑: 只是为了澄清,我不是参照一般使用中的常量的源代码。我很具体的讲 调试方案的问题 可能来达到使用六价值观,与特定的例子 0xDEADBEEF
.
解决方案
我认为提出的关切的IP地址格式问题今天早些时候不是有关使用六角文字一般,但是具体采用的0xDEADBEEF.至少,那是我的方式阅读。
有一个问题与使用0xDEADBEEF特别是,虽然在我看来,它是一个小。问题是,许多调试和运行系统已经选择这个特别的价值作为标记价值来表示的未分配堆的坏上的指针叠,等等。
我不记得掉我的头顶只是其中的调试和运行系统使用这一特定价值,但我已经看到它使用这种方式若干次多年。如果你正在调试在这些环境中,存在0xDEADBEEF不断在你的代码将是没有区别的价值观在未分配RAM或什么的,所以最好你不会有有用的RAM堆放场,并且在最糟糕你会得到警告,调试器。
无论如何,那是什么我觉得原来的评论意思时,他告诉过你这是个坏为"用于各种调试情况。"
其他提示
有一个在使用比任何其他种字面文字六角没有更多的危险。
如果您的调试会话结束执行数据的代码没有你就打算,在你痛苦的世界是无论如何。
当然,还有正常的“魔力值”与“精心命名常量”代码异味/洁净度的问题,但是这并不是真正的那种危险,我认为你是在谈论。
除了少数例外,没有什么是 “恒定”。
我们更愿意称他们为“慢变量” - 如此缓慢,我们不介意重新编译改变他们自己的价值变动
但是,我们不想通过一个应用程序或测试脚本,其中每个实例都有不同的意义有0x07的的所有许多情况下。
我们想要把一个标签上,使得它完全明确每个常量是什么意思。
if( x == 7 )
什么是“7”指的是在上面的语句?它是一回事
d = y / 7;
是相同的含义的“7”?
测试用例稍有不同的问题。我们不需要一个数字文本的每个实例的广泛,细致的管理。相反,我们需要的文件。
我们可以 - 在一定程度上 - 解释,其中“7”通过在代码的提示的一点点从来自
。assertEquals( 7, someFunction(3,4), "Expected 7, see paragraph 7 of use case 7" );
一个“恒定”应当说明 - 并命名 - 正好一次
A“结果”,在一个单元测试是不一样的东西作为一个常数,并且需要一点点的关心解释它来自何方。
一个十六进制文字不大于十进制字面像1.不同的值的任何特殊的意义是由于特定程序的上下文。
有没有理由,你不应该分配0xdeadbeef
一个变量。
但临头谁试图分配十进制3735928559
,或八进制33653337357
,或者最糟糕的程序员:二进制11011110101011011011111011101111
<强>大端或小端吗
一个危险是当常数被分配到一个阵列或结构具有不同尺寸的构件;在端编译或机器(包括JVM VS CLR)的-ness会影响字节的顺序。
此问题是不恒定的值的真,也当然可以。
下面是一个,诚然做作,例子。什么是的值的缓冲液[0] 最后一行之后?
const int TEST[] = { 0x01BADA55, 0xDEADBEEF };
char buffer[BUFSZ];
memcpy( buffer, (void*)TEST, sizeof(TEST));
我看不出与使用它作为一个值的任何问题。它只是毕竟一个数字。
有一个在使用硬编码十六进制值用于在正确的上下文的指针(如您的第一例)没有危险。特别是,这样做很低级的硬件开发的时候,这是你访问内存映射寄存器的方式。 (虽然这是最好的给他们用#define名称,例如)。但在应用层面,你不应该在任何时候需要做这样的分配。
我用CAFEBABE 我还没有看到它之前被任何调试器。
int *i = 0xDEADBEEF;
// god knows if that location is available
int i = 0xDEADBEEF;
// what can go wrong?
的危险,我看到的是同在这两种情况:你已经创建了一个标志值,没有直接上下文。没有什么有关 i
在任何一种情况下,将让我知道100,1000或10000线,那里是一个潜在的重要标志的价值与它相关联。什么你已经栽了一个地雷的错误,如果我不记得要检查它在每一个可能的使用,我可以面临着一个可怕的调试的问题。每一个使用的 i
现在必须是这样的:
if (i != 0xDEADBEEF) { // Curse the original designer to oblivion
// Actual useful work goes here
}
重复上述所有7000情况下需要使用 i
在你的代码。
现在,为什么是上述比这更糟糕?
if (isIProperlyInitialized()) { // Which could just be a boolean
// Actual useful work goes here
}
至少,我可以发现几个关键问题:
- 拼写:我是个可怕的打字员。多么容易你会点0xDAEDBEEF在码审查?或0xDEADBEFF?另一方面,我知道,我的编制将呕吐后立即isIProperlyInitialised()(插入的强制性 s 与 z 在这里的辩论).
- 曝光的含义.而不是试图隐藏自己的旗子在代码中,你已经有意地创造了一个方法,其余的代码可以看到。
- 机会耦合.这是完全可能的,一个指针或基准是连接到一个松散定义的高速缓存。初始化检查可以超载来检查一下如果价值是在高速缓存,然后试着把它回到缓和,如果所有的失败,返回错误的。
总之,这只是为方便编写代码,你真正需要的,因为它是创造一种神秘的魔法的价值。代码维护人的未来(人相当有可能将您)会感谢你的。