在一本书中有一个关于静态/非静态对象的例子。
char buf[MAX];
long count=0;
int i=0;
while(i++<=MAX)
if(buf[i]=='\0') {
buf[i]='*';
++count;
}
assert(count<=i);
据说有时代码会将buf数组的末尾写入count并使断言失败。然后讲述将计数声明为静态并解决问题(注意:作者将此作为一个不好的解决方案示例)无论如何,除了一个坏的例子,我无法弄清楚问题是如何发生的,以及如何解决它作为声明算作静态。
答案 0 :(得分:4)
这不仅仅是糟糕的解决方案,而是非解决方案。您不能索引数组的边界。如果这样做,则在实现正确的C ++程序方面存在不可解决的问题。
您可能会在常见的C ++实现中看到,有时count
会在buf
之后直接放入堆栈。因此,如果你过度索引然后写,你可以修改count
,然后任何纯粹基于直接写入它的count
值的假设不再正确,因为有写通过过度索引操作来实现它。
如果您现在将变量设为static
,则在程序的其他部分中分配(通常为{0}初始化的.bss
和其他初始化数据的.data
,常见实现上的count变量将不再分配在数组旁边,这将导致另一个事件发生:而不是覆盖count
,您可能会覆盖数组旁边的任何内容。
答案 1 :(得分:3)
该示例依赖于内存中变量的特定布局,即count
恰好位于buf
之后。通过使count
静态,它被放置在内存的不同部分,而其他东西则被破坏。问题没有消失,症状刚刚改变。
答案 2 :(得分:1)
约翰内斯的回答是正确的。
但是,为什么将count
声明为static
可能会使出现。当count
被声明为非static
时,它通常会在内存中buf[]
之后立即生效(在堆栈上)。但是,当声明为static
时,它不会在堆栈中,因此当您在buf[]
的末尾写入时不会损坏。
答案 3 :(得分:0)
我同意,如果超过数组边界,则会导致超出范围的异常。或者在非托管语言(如C / C ++)中,你可能最终写入/读入下一批内存地址,我的非空终止字符串的内存运行到另一个对象内存中并不好玩。
我有点好奇你的静态对象在哪里,你把它们全部声明为变量,看不到静态对象。
上面的代码应该总是超过数组,因为我首先检查了max,然后增加了i,这使得我增加了一个最大值,给你一个1的错误。
答案 4 :(得分:0)
我想阅读这本书,但我想它会显示“巫毒编程”的例子,你会尝试随机的东西,直到它停止破坏,并称之为成功。
正如其他地方所提到的,通过将其声明为静态来做的所有事情都是移动计数到不同的地方,这意味着断言可能会通过。对于没有经验的程序员来说,这足以提交,此时您在生产环境中有缓冲区溢出代码。
当然,我希望“i”会被覆盖,这会更糟糕,因为它是循环的控制变量,但我可能错了。