昨天晚上赶工开发一个软件,偶尔发现下面这个程序居然通不过VC++ 6.0的编译!!!最先我还以为是我的代码不符合C++标准呢!后来仔细阅读了C++标准,才发现这是VC++ 6.0的一个Bug。自从C++标准定案以来,namespace关键字和语法已被各大C++编译器厂商所支持。VC++ 6.0也不例外。VC++ 6.0完全支持namespace关键字和语法。但是,VC++ 6.0却错误地实现了namespace关键字和语法。C++标准规定:namespace可以存在于多个编译单元中。只要namespace的名字相同,编译器就会在编译的时候自动合并所有同一名字的namespace到一个单独的namespace中。而且,凡是在某个名字空间内部使用了using namespace XXX;的,XXX中的所有声明在这个名字空间内部都自动可见。在同一个作用域内,多次引用using namespace XXX;是无害的。我的这段代码按照C++标准来说绝对没有问题,在VC++ 6.0 (SP6)下面编译通不过。但是,在VS 2003下面却可以编译链接通过且完全无误。据此可以断定:VC++ 6.0编译器中的这个Bug是确凿无疑的!看来微软内部的官僚主义作风还是存在的,VC++ 6.0的补丁都打了6个了,最后一个补丁直到2004年才推出,居然还隐藏着这么一个不大不小的问题。#include <string>namespace tk
{
using namespace std;    int a;
}namespace tk 
{
    int b;
}namespace tk 
{
using namespace std;int foo()
{
    string str = "Hello";    return (int)str.size();
}}int main()
{
    return 0;
}VC++ 6.0关于namespace关键字Bug的过程分析(这可是我昨晚苦苦思索分析5个小时的心血啊!为了搞清楚微软究竟在什么地方犯了错误,我屡次提出假说,屡次被实验结果所否定,搞得我有好几次都想放弃了事,但又心有不甘。最后还是硬着头皮坚持了下来,终于得出了和实验结果完全一致的结论。激动的泪花)1,如果一个名字空间不引用using-derective,那么不会有任何问题。所有的同名名字空间会按照先后顺序集合在一个大的同名名字空间中,然后编译链接。所有的问题都出在危险的using-derective上面。2,以下所有的说明都默认是在同一个编译单元内。假定这个编译单元内存在若干个不同的名字空间。每个不同的名字空间又包含若干个同名的namespace。同名的namespace以下简称“同名空间”。3,根据同名空间内包含的using-derective,可以对同名空间进行不同的分类,每一类都包含有第一次出现某个using-derective的namespace和后面的所有同名空间,不同后面的同名空间是否包含这个using-derective。这样的同名空间集合以下简称“同一类”。以下的分析对每一个“同一类”都适用。4,同一类中的各个namespace,按照出现的先后顺序,分别称为1号空间,2号空间,3号空间,4号空间等等。5,1号空间暴露了using-derective所包含的声明。2号空间则完全隐藏了1号空间由using-derective所暴露的所有声明,但是其他的非using-derective声明则继承了下来。原因未知。所以,2号空间一定要使用自己的using-derective才能正常使用其中的声明。6,从3号空间开始,后面的所有同一类空间所包含的using-derective都会在编译之前被优化清除,因为编译器会自动暴露1号空间的using-derective所包含的声明。7,3号空间如果包含一个using-derective,那么1号空间中由这个using-derective所暴露的声明会被隐藏起来,但是1号空间中其他的声明不会被隐藏。又由于3号空间的using-derective在正式编译之前就被优化清除了,所以3号空间反而看不见由这个using-derective所暴露的声明了。所以,3号空间一定不能使用using-derective。8,4号空间及以后的空间,是否包含using-derective,结果都一样。因为编译器会自动优化清除它,并且自动暴露1号空间中的相关声明。9,同一类的所有namespace,按照出现的先后顺序,其中包含的非using-derective声明自动在整个同名空间内有效。包括在2号空间内出现的非using-derective声明。10,结论:针对2号空间和3号空间,编译器采用了某种特殊的策略。事实证明这种策略是错误的。
 

解决方案 »

  1.   

    我坚持认为这是微软的Bug。因为:1,如果VC++ 6.0不支持namespace语法,也就是说没有实现C++标准中的namespace部分。那么,我们不会认为这是它的Bug。但是,VC++ 6.0的确宣称它实现了namespace语法,关于这一点可以查阅MSDN得以证明,也可以编写几个小程序验证。2,如果一个编译器宣称它实现了某项C++标准,然而事实又证明它没有正确地实现这项标准。那么称其为Bug是恰如其分的。因为所谓Bug无非就是软件没有正确实现其预期功能的一种说法。是否知道Bug产生的确切原因不会影响对这个问题本身的Bug判断。因为判断Bug的标准是客观的,有正反两方面的判决性试验结论支持,不是我的主观臆断。3,我上面的10条分析结论是我自己根据大量的实验结果总结出来,这10条结论经受住了至少数百次的代码实验验证,没有发现反例。这10条分析结论只是在一定程度上准确地描述了VC++ 6.0的Bug表征,并不能说明微软的设计意图。但我坚信,微软的设计意图必有失察之处。