Microsoft Visual C++ 是微软公司Visual Studio 开发套件中的一出重头戏与前一个版本相比其革新性的集成开发环境与C++编译器带来了有许多改变在本文中主要讲解程序员在升级程序时可能会遇到的一些不同之处及变化而这些变化很可能会使老一点的程序不能通过编译总之这些变化绝不是偶然发生的其背后都有强大的理论依据在支撑所以使用Visual C++的程序员在升级之前一定要弄清楚这些变化
Visual C++中已经发生的变化
微软Visual C++工作小组在对其产品作出修改之前已经过充分的考虑同时也顾及到了这些改变会对以前的代码造成的影响虽然如此但有以下理由支持在新版本中作出的这些改变
Visual C++ 其中一个最重要之处就是更加遵循ISO C++标准可更好地跨平台移植代码或集成进其他工具中如声明在for循环中的变量生命期及变量类型现在也遵循C++标准了而且在默认设置中就是遵循ISO C++标准的正是因为此在一些老代码中过去可行的一些方法现在可能要作出必要的修改才能通过编译了
在这几年中安全性是一个热门的话题而且在将来也会得来越来越多的重视C++语言赋于了程序员无所不能的能力但凡事总有两面性为减少代码中的安全问题也为减少代码中错误产生的可能性Visual C++ 作出了一系列的改变首先引入了安全CRT及不推荐使用的非安全API等概念而且在默认状态下Visual C++ 也会进行代码安全检查
Visual C++ 增强了适用性这也使得可更方便地升级本身的二进制代码成为可能而且也更加容易进行产品的漏洞修补
可维护性也是一个促进Visual C++变化的原因之一例如低价值的功能已经从产品中消失以减少在将来维护它们的可能性一个例子就是Visual Studio 中已经移除了单线程CRT因为已经不再需要它了以前为维护单线程CRT所花费的时间现在可以用在更重要的事情上了
最后其中的某些变化是为了增强Visual C++编译器的可靠性为达此目的微软公司此次保证了Visual C++中有明确定义并一致的行为
当然也要避免某些变化此次Visual C++的大多数变化都是在代码安全层面上如果这些变化向后影响到二进制代码的兼容性那么就会尽量避免因为源代码兼容性总是在二进制代码兼容性之前被发现的另外如果某些变化致使人们不想采用或升级到版那么这种变化也要避免因为这会导致软件项目的总成本增加最后编写代码方式的改变也要在成本上证明是值得的否则就没有必要去实现它了
Visual C++库的十项突破性变化
Visual C++ 库已经发生了一系列的变化可能会对现有的程序有所影响在升级到Visual C++ 之前必须要确定程序中没有这些问题
参数的有效性
在C运行时库中加入了一些代码以检查参数的有效性例如如果传递的目标缓沖区大小不足以strcpy使用通常这是在冒安全风险而新版本此时则会调用一个非法参数处理程序在release版中会调用DrWatson而在debug版中会产生断言(assert)当然只要程序中传递的参数都是有效的就不会有什么问题了
对非安全API的警告
在Visual C++ 中CRT中的一组函数已不再建议使用而应使用新提供的安全版本大多数这些不建议使用的函数如果使用不当将会导致缓沖区溢出或其他安全问题这些函数如strcpystrcat等等这些函数新的安全版本都在函数名后加了一个_s后缀以方便识别如strcpy_swcscpy_smbscpy_scalloc_s和strcat_s这些函数
如果想继续使用老版本非安全的函数可在源代码开始处加上#define value of _CRT_SECURE_NO_DEPRECATE(此处value代表某一数值)然而还是建议大家升级代码使用新的安全函数
迭代器越界
受检查的迭代器(checked iterators)和调试迭代器(debug iterators)也因为安全的原因进行了相应的更新如果迭代器越界则相应会调用一个非法参数处理程序
再次提醒可以通过抛出一个越界异常来避免产生非法参数问题在代码中加入#define value of _SECURE_SCL_THROWS并把value值设为这样就不会调用非法参数处理程序而是产生一个异常了
也可以通过设置#defined value of _SECURE_SCL值为零关闭此迭代器检查通常默认情况下此选项是打开的
time_t类型
time_t类型通常用于显示从年开始以来的秒数直到Visual C++ (即Visual C++ )time_t类型都被定义为一个long而到了Visual C++ 中已被定义为一个位类型可用于显示一直到年的时间了
链接到CRT
托管应用程序现在不能静态链接到CRT以往在Visual C++ 和中(指Visual Studio NET 与)可以生成静态链接到CRT的CLR程序而在Visual Studio 却行不通
单线程CRT支持
在Visual Studio 中已经取消了单线程CRT支持而且用发展的眼光来看未来大多数的人还是愿意使用线程安全的多线程代码
在线程中可使用_nolock后缀来优化代码但同时这些函数是非线程安全的
异常处理
有两种类型的异常处理可供选择/EHa(异步的)和/EHs(同步C++异常)在以前如果使用了/EHs那么在一个catch(…)块中也许可能也许不可能捕捉到结构化异常因为此行为是没有定义且不可靠的现在再使用/EHs时就可保证不会捕捉到结构化异常如果想与以前版本的Visual C++保持一致并且捕捉异步结构化异常还是应该在编译时使用/EHa
初始化顺序
以往如果代码中同时有托管与本地全局变量及对象那么初始化顺序是不确定的如代码中存在托管对象与本地对象互操作就不能保证哪一个对象先初始化了现在Visual Stuio 可保证所有的本地全局变量及对象先初始化然后才初始化托管全局变量及对象
printf
就目前来说printf中的%n格式化指示符一般用于指定输出的字符个数这已经确认为一个安全隐患并且已禁用但可以使用set_printf_count_output来启用它通过传递给set_printf_count_output一个零值()可禁用它而传递任意一个其他值可再次启用
swprintf函数
为与C++标准保持一致对swprintf函数也作了修改现在它已遵循C++标准了在C++中通过适当的参数可实现重载这个函数的老版本已不再建议使用因为在C中是不允许重载的因此如果使用老格式将会返回一个错误
编译器中的突破性变化
除了那些会影响到库的变化之外也有一些变化会影响到编译器以下是Visual C++ 中编译器的主要变化需再次提醒的是此处并没有列出所有的变化但却是微软公司VC++使用者及内部合作者所确认的关键性变化
指向成员的指针
在之前的版本中一个指向成员的指针不需使用取址操作符(&)就能获取现在Visual C++ 已经严格按照标准必须要使用取址操作符这也有助于消除潜在的运行时错误但也导致了MFC库的许多地方需要修改同时意味着可能会对现有的程序造成影响
范围限制规则
在for循环声明中默认情况下不强制执行范围限制规则在之前的版本中for循环中变量的生命期将会延续到循环之外为与标准兼容for循环中定义的变量现在只限定在for循环内使用
wchar_t类型
现在wchar_t已为默认内置类型这就是说也许在以前wchar_t可能会被当作一个unsigned short因为它还不是内置类型所以当与那些有wchar_t类型变量的文件作符号比较时很可能会导致问题在Visual C++ 中wchar_t已是一个内置类型也就是说需要确定以前对wchar_t的用法不会导致转译为一个unsigned short
异常处理
为了与库的变化保持一致编译器已作了一些修改以便不会捕捉到结构化异常所以为与以前代码保持兼容还是应该使用/EHa
参数属性
为了提供更健壮的属性也是为了代码的健壮性编译器现在将会检查类型枚举等等的属性这意味着以前的代码可能会在属性方面碰到一个从未有过的编译器错误
默认为int
为遵循C++标准对没有类型声明的变量或函数已不再默认为int类型但在C语言中仍然可以C++语言中已不行这甚至也影响到了微软公司自身的代码包括NT系统的代码所以最好的方式还是显式声明
关于C的托管代码
C语言编译器一般不可能创建CLR的托管代码因为C语言不是面向对象的它不符合CLR所使用的模型因此任何以C语言来编译的代码都会与CLR编译器设置沖突例如如果在编译时使用/TC设置而且又设置了CLR就会导致沖突
面向CLR的新语法
通过设置/clr编译选项C++编译器只接受新语法这将强制推广加入到Visual C++ 中的新语法同时也会废弃掉老代码
安全检查
在安全越来越得到重视的今天安全检查选项/GS在默认情况下就是打开的还是有一定道理的在Visual C++中默认情况下将会使用/GS选项
结论
本文列出了微软公司已确认的Visual C++ 中的一些关键性变化虽然不是所有的变化也不是最有可能沖击到代码的变化但此处所列出的项目将最有可能导致问题的产生
归根结底在升级或用新版编译器对程序作修改之前必须先试着编译现有程序以确认代码能通过编译否则就不可避免要动手修正源代码中存在的问题