|
|
偶然在一次编译中,发现编译器没有因为宏名的错误拼写报错,这引起了我强烈的好奇心,于是试着在VC++和g++几个编译器里试了以下代码:
#include <iostream>
int main()
{
#if ABCDEFG == FFFFFF
std::cout << "test1"<< std::endl;
#endif
#if ABCDEFG == FFFFFF + 1
std::cout << "test2"<< std::endl;
#endif
#if ABCDEFG + 1 == FFFFFF + 1
std::cout << "test3"<< std::endl;
#endif
#if ABCDEFG + 5 == FFFFFF + 6
std::cout << "test4"<< std::endl;
#endif
#if ABCDEFG + 6 == FFFFFF + 6
std::cout << "test5"<< std::endl;
#endif
return 0;
}
编译正常通过,输出结果:
test1
test3
test5
说明这几个编译器将未定义标识符设为某个固定的默认值,再次编码:
#include <iostream>
int main()
{
#if ABCDEFG == 0
std::cout << "test1"<< std::endl;
#endif
#if FFFFFF == 0
std::cout << "test2"<< std::endl;
#endif
#if ABCDEFG == 1
std::cout << "test3"<< std::endl;
#endif
#if FFFFFF == 1
std::cout << "test4"<< std::endl;
#endif
return 0;
}
编译通过,输出结果为:
test1
test2
从而进一步证实:这几个编译器都将未定义标识符设为默认0值。
紧接着查看C++标准文档,在预编译指令章节中发现了关于未定义标识符的规定:
After all replacement due to macro expansion and the defined unary operator have been performed, all remaining identifiers and keywords, except for true or false, are replaced with number 0.
恍然大悟,原来是C++标准的规定。先前的疑问消释了,但很快另一个令人费解的问题也来了——为什么标准要这么规定?一个标准的制定,总该有它的理由,按照思维习惯,我们会禁不住想——这样做有什么好处?反正我是实在想不出在宏编译中碰到未定义标识符设为0会给程序员带来什么好处,而且我认为,这是条非常糟糕的标准定义!
既然在编译代码中要坚持而且必须要显式声明,为什么宏编译指令中碰到未定义标识符却将其置为0值,这本身就是一种怪异的不一致性,而且还隐藏着更致命的风险,试想一下以下的情况:
#if _MSC_VER == 1200
... //CODE
#endif
这段代码将在VC6中被编译。
但如果程序员因为疏忽,写了以下代码:
#if MSC_VER == 1200
...
#endif
MSC_VER是一个未定义的标识符而不是宏,它的值为0。很显然,这段代码将被忽略,由于开发者错误的宏名拼写,就是未定义的标识符和已定义的宏之间的差别。程序可能产生难以检查的异常现象,而开发者却难以凭直觉检查出来。。。
但遗憾的是,标准委员没制定“防呆”规范,反而似乎在鼓励这种"带着风险的自由",这并不是C/C++一贯的自由风格,因为此时的这个自由跟其他的自由不一样,它看起来没有任何的意义。
实在想不通,C++标准委员会为什么做出如此规定。这样的标准意义在哪呢?这样的标准有何合理之处? |
|