98年的VC6到08年的VS2008-从atoi的用法差别看UNICODE的使用
来源:互联网 发布:matlab subs 矩阵 编辑:程序博客网 时间:2024/05/17 01:16
由于平时写的较多的是工业设备程序,所以用的XP+VC6比较多,最近写一个小程序,用上了VS2008。之前也用过很长时间的VS2008,没出什么大问题,但是今天将之前在VC6上写的一个工作正常小接口程序拿过来直接用居然不行。自认为一直很注意C++语法标准的问题,也比较清楚VC6和VS2008的差别,可是试了很长时间都没发现问题,最后解决了问题发现是UNICODE的问题。
在这里记下问题,希望对遇到相同问题的人有帮助。
问题:用atoi函数将一个字符串转换为一个整数
基本代码如下
TCHAR szBuffer[10] = TEXT("10");printf("%d", atoi(szBuffer));在VC6中这段代码没有问题,但是在VS2008中就会报错error C2664: 'atoi' : cannot convert parameter 1 from 'unsigned short [10]' to 'const char *'
猜想为UNICODE问题,为了解决问题,我写了完整的测试用例
在VC6中代码如下:
#include <STDIO.H>#include <windows.h>int main(int argc, char *argv[]){char string1[10]="123";WCHAR string2[10]=L"156";TCHAR string3[10]=TEXT("456");printf("string1=%d, string2=%d, string3=%d\n", atoi(string1), atoi(string2), atoi(string3));return 0;}编译出错,检查为atoi(string2)调用错误,报错为error C2664: 'atoi' : cannot convert parameter 1 from 'unsigned short [10]' to 'const char *'
那我就强制转换一下
改为
printf("string1=%d, string2=%d, string3=%d\n", atoi(string1), atoi((const char *)string2), atoi(string3));编译正常,结果显示如下
string1=123, string2=1, string3=456等等,为什么只输出了1,为了验证问题接着用_wtoi输出如下
string2=156这就对了,_woti是针对UNICODE编码的函数,atoi是针对ASCLL编码的函数
查MSDN,两者的声明分别是
int atoi( const char *string );
int _wtoi( const wchar_t *string );这里char是ASCLL编码占一个字节,wchar_t为UNICODE编码占两个字节,在微软头文件中可以查到TCHAR、wchat_t和unsigned short是一样的,在故我们使用atoi(string2)时会报错,默认是无法进行UNICODE两个字节向ASCLL单字节的隐式转换的,当我使用(const char *)将string2进行转换时,由于这时候编译器类型检查是对了,但是结果有问题。
理解为什么156强制转换后输出为1这个问题,需要从内存上来看
对于string2为UNICODE编码每个字符占两个字节,"156“对应的内存为6个字节,查询ASCLL表为31 00 35 00 36 00(注意存储结构,低位在前)
那么我们强制转换后,它对应翻译为ASCLL字符串中的字符就依次是'1'、'\0'、‘5’、‘\0’、‘6’、'\0'
atoi是以'\0'检测字符串结尾的,显然这里输出为1
那么,下面我将这段代码搬到VS2008中
#include <STDIO.H>#include <windows.h>int main(int argc, char *argv[]){char string1[10]="123";WCHAR string2[10]=L"156";TCHAR string3[10]=TEXT("456");printf("string1=%d, string2=%d, string3=%d\n", atoi(string1), atoi((const char *)string2), atoi(string3));printf("string2=%d\n", _wtoi(string2));return 0;}保存,依旧是error C2664: “atoi”: 不能将参数 1 从“TCHAR [10]”转换为“const char *”
检测发现atoi(string3)出现问题,联系之前的结论很显然这里的TCHAR代表的是WCHAR才会出现问题
我们知道只有定义了UNICODE标识符,TCHAR才会表示为WCHAR,由此可以发现VC6的默认编码不是UNICODE而在VS2008中默认编码为UNICODE
可以在VC6的工程->设置中添加UNICODE标识
这时候刚才运行正常的问题现在会报和VS2008一样的错误
可以在VS2008的项目->属性中取消设置UNICODE标识
这时候编译正常,运行结果和VC6一样
结论:
所以,这里总结来说可以看到从VC6到VS2008编译器倾向于引导开发者习惯UNICODE编码的开发,这样在开发多国语言的程序版本时不会出现乱码的问题。对于我们开发者来说我们当然期待微软像提供lstrlen这样的自适应编码的函数,但是不知道出于什么原因,貌似现在微软没有提供类似的函数,那就必须要求我们针对当前的程序编码使用对应的函数(ASCLL使用atoi,UNICODE使用_wtoi),否则程序出现莫名其妙的结果和错误往往让我们不知所措。作为笔者,推荐使用UNICODE编码和对应的函数,毕竟现在来说使用ASCLL编码省下来的那点内存开销值五毛钱吗?
补充:没认真看MSDN,谢谢baita96指出,微软提供了自适应函数_ttoi,如果你对程序可移植性没那么高要求,就想在Windows在运行的话用它就不会出错了。
测试用例完整源代码
原创,转载请注明来自http://blog.csdn.net/wenzhou1219
- 98年的VC6到08年的VS2008-从atoi的用法差别看UNICODE的使用
- VC6到VS2008的变化
- 从VC6.0 到vs2008 出现的问题
- 从VC6 VS2008遇到的问题总结
- VC6项目移植到VS2008的若干问题——好的代码,从我做起,从现在做起。
- 从汇编看模块的用法和函数传递引用时的差别
- 从Bitmap的用法看HTC one和Samsung Note2的差别。
- 项目工程从VC6.0迁移到VS2008的几个体会
- 从VC6.0过度到VS2008遇到的基础问题:多字节
- 从VC6.0转到vs2008的一些问题
- 从VC6.0转到vs2008的一些问题
- 从vc6.0转到vs2008出现的错误
- ATOI的用法
- atoi函数的用法
- atoi的用法
- vc6转换到vs2008 fopen出现字符集转换的问题
- vc6转换到vs2008 fopen出现字符集转换的问题
- VC6.0移植到VS2008后的错误总结
- Java串口通信——Error: no rxtxSerial
- utlrp.sql脚本
- Java对象的强、软、弱和虚引用
- Struts2页面到action的三种传值方式
- JDBC入门开发过程
- 98年的VC6到08年的VS2008-从atoi的用法差别看UNICODE的使用
- 做事情学会批量处理能让你节约大量的时间
- linux文件系统描述
- Hive 元数据“waiting for table metadata lock”
- 软件测试
- Qt进程间共享内存例子
- JavaScript笔记NaN
- 無形과 有形 (易學原理總論韓長庚)
- 第十七周 体会函数参数传递2