ATL字符串转码的陷阱

ATL 2013 ,纯静态版本的ATL ATL+WTL,Windows平台仍然是一对锋利的组合。 主要特点: http://blogs.msdn.com/b/vcblog/archive/2013/08/20/atl-and-mfc-changes-and-fixes-in-visual-studio-2013.aspx One of the major changes we made was to eliminate the ATL DLL altogether. All ATL code is now static, either in the header files or in the ATL static library. We also reduced the amount of code in the ATL static library substantially, so there are no longer multiple static libraries for debug/release mode or Unicode/ANSI character set. There is only one ATL static library that is common to all configurations. 立即下载

在代码中经常使用UTF8与Wide Char的转换,每次手工调用WideCharToMultiByte转换很是麻烦,于是参考ATL的W2A、A2W这样的宏,自己写了两个宏:UTF82W、W2UTF8。

我写的UTF82W、W2UTF8与ATL的W2A、A2W一样,都是使用_alloca在栈上开辟临时空间存放转换结果的。后来,由于在使用中出现了一个函数中转换的次数过多导致栈溢出的问题。于是想改进这个宏。

比较新的ATL库里还有W2A_EX,这个宏第二个参数是本次转换在栈上最大开辟空间的长度(其实看过代码就知道,它无视了你的这个长度,总是使用一个硬编码的_ATL_SAFE_ALLOCA_DEF_THRESHOLD这个宏指定的1024作为最大开辟空间长度)。

我想要的正是这个功能。但上次仿写W2UTF8已经写伤了(看了实现你就知道了)。翻ATL源代码,找到好东西了:W2A_CP_EX,这个宏与W2A_EX类似,使用时多一个参数,用于指定转换的代码页。由于用WideCharToMultiByte来转换UTF8串时,是通过指定一个叫CP_UTF8的特殊代码页来实现的,于是,我天真的认为,只要指定CP_UTF8来使用W2A_CP_EX,就不用自己去写W2UTF8_EX了。

说用就用。在测试代码中试了一下,果然可以转,没多想就用上了。结果没几天,程序出现错误了,用这个宏,很多串都会转换失败。查代码,发现在这个宏调用WideCharToMultiByte时失败,LastError为0x0000007a:The data area passed to a system call is too small。看现象应该是开辟的空间不够大。

这怎么可能呢?!查代码!结果让我大跌眼镜:ATL的W2A_CP_EX宏在转换前计算需要开辟的空间尺寸时,没有用WideCharToMultiByte本身来计算,而是(出于什么我不清楚的设计的目的)使用了lstrlen得到串中的字符个数后乘以2(sizeof(WCHAR))当做新串空间长。明显的,如果串中包含中文,转换后是3个字节,而不是2个字节。于是,空间不够是当然的了。

我认为,ATL这么做,主要是从性能上考虑,lstrlen不需要进行实际的转换,只是计算串中的字符数,性能当然好过WideCharToMultiByte。

但这样的话,就出现了抽象泄漏:其它API指定代码页时,可以使用CP_UTF8,但这里指定代码页时就不能使用,你得知道它的实现才能正确使用。

一个好的设计,应当是不会被用错的。调用两次WideCharToMultiByte,时间复杂度不会变化。我认为这里没必要为了性能牺牲抽象。

一段好的代码,应当是严谨的。遵守API的使用条件非常重要。WideCharToMultiByte要求的转换后空间大小,只有他知道(你要知道还用他转换什么劲呀),那就应当让他告诉你准备多大的空间。

事情的结果:最终,我自己又仿照W2A_CP_EX重新实现了W2UTF8_EX,不同的是:我使用了WideCharToMultiByte来计算所需的空间。

 

附:

ATL的实现:

#define A2W_CP_EX(lpa, nChars, cp) (/

    ((_lpa_ex = lpa) == NULL) ? NULL : (/

        _convert_ex = (lstrlenA(_lpa_ex)+1),/

        FAILED(::ATL::AtlMultiply(&_convert_ex, _convert_ex, static_cast<int>(sizeof(WCHAR)))) ? NULL : /

        ATLA2WHELPER(   /

            (LPWSTR)_ATL_SAFE_ALLOCA(_convert_ex, _ATL_SAFE_ALLOCA_DEF_THRESHOLD), /

            _lpa_ex, /

            _convert_ex / sizeof(WCHAR), /

            (cp))))

 

#define W2A_CP_EX(lpw, nChars, cp) (/

    ((_lpw_ex = lpw) == NULL) ? NULL : (/

        _convert_ex = (lstrlenW(_lpw_ex)+1),/

        FAILED(::ATL::AtlMultiply(&_convert_ex, _convert_ex, static_cast<int>(sizeof(WCHAR)))) ? NULL : /

        ATLW2AHELPER(   /

            (LPSTR)_ATL_SAFE_ALLOCA(_convert_ex, _ATL_SAFE_ALLOCA_DEF_THRESHOLD), /

            _lpw_ex, /

            _convert_ex, /

            (cp))))

 

我的UTF8与Wide Char转换宏:

 

#define USES_CONVERSION_UTF8 /

    USES_CONVERSION_EX; /

    int _convert_rhyme = 0; /

    (_convert_rhyme); /

    UINT _acp_rhyme = CP_UTF8 ; /

    (_acp_rhyme); /

    LPCTSTR _lpt_rhyme = NULL; /

    (_lpt_rhyme); /

    LPCSTR _lputf8_rhyme = NULL; /

    (_lputf8_rhyme)

 

 

#define UTF82W_EX(lputf8, nChars) (/

    ((_lputf8_rhyme = lputf8) == NULL) ? NULL : (/

    _convert_rhyme = MultiByteToWideChar(CP_UTF8, 0, _lputf8_rhyme, (int)(strlen(_lputf8_rhyme)), NULL, 0),/

    (_convert_rhyme == 0) ? NULL : /

    (RhymeUTF82WideCharHelper( /

    (LPWSTR)_ATL_SAFE_ALLOCA((_convert_rhyme + 1) * sizeof(WCHAR), nChars), /

    _lputf8_rhyme, /

    _convert_rhyme + 1))))/

 

 

#define UTF82W(lputf8) UTF82W_EX(lputf8, _ATL_SAFE_ALLOCA_DEF_THRESHOLD)

 

 

#define W2UTF8_EX(lpwide, nChars) (/

    ((_lpt_rhyme = lpwide) == NULL) ? NULL : (/

    _convert_rhyme = WideCharToMultiByte(CP_UTF8, 0, _lpt_rhyme, (int)(wcslen(_lpt_rhyme)), NULL, 0, NULL, NULL),/

    (_convert_rhyme == 0) ? NULL : /

    (RhymeWideChar2UTF8Helper( /

    (LPSTR)_ATL_SAFE_ALLOCA((_convert_rhyme + 1) * sizeof(char), nChars), /

    _lpt_rhyme, /

    _convert_rhyme + 1))))/

 

#define W2UTF8(lpwide) W2UTF8_EX(lpwide, _ATL_SAFE_ALLOCA_DEF_THRESHOLD)

 

 

    LPWSTR RhymeUTF82WideCharHelper(LPWSTR lpszWideString, LPCSTR lpszUTF8String, size_t nWideCharCount)

    {

        _ASSERTE(lpszWideString != NULL);

        _ASSERTE(lpszUTF8String != NULL);

        _ASSERTE(nWideCharCount <= TypeLimit<int>::Max());

        _ASSERTE(strlen(lpszUTF8String) <= TypeLimit<int>::Max());

 

        size_t nUTF8Length = strlen(lpszUTF8String);

 

        if(lpszWideString == NULL || lpszUTF8String == NULL ||

            nWideCharCount > TypeLimit<int>::Max() ||

            nUTF8Length > TypeLimit<int>::Max())

        {

            return NULL;

        }

 

        int nConverted = MultiByteToWideChar(

            CP_UTF8,

            0,

            lpszUTF8String,

            (int)(nUTF8Length),

            lpszWideString,

            (int)(nWideCharCount));

 

        if(nConverted == 0 && ERROR_NO_UNICODE_TRANSLATION == GetLastError())

        {

            return NULL;

        }

        lpszWideString[nConverted] = L'/0';

        return lpszWideString;

    }

 

    LPSTR RhymeWideChar2UTF8Helper(LPSTR lpszUTF8String, LPCWSTR lpszWideString, size_t nUTF8ByteCount)

    {

        _ASSERTE(lpszWideString != NULL);

        _ASSERTE(lpszUTF8String != NULL);

        _ASSERTE(nUTF8ByteCount <= TypeLimit<int>::Max());

        _ASSERTE(wcslen(lpszWideString) <= TypeLimit<int>::Max());

 

        size_t nWideCharCount = wcslen(lpszWideString);

 

        if(lpszWideString == NULL || lpszUTF8String == NULL ||

            nUTF8ByteCount > TypeLimit<int>::Max() ||

            nWideCharCount > TypeLimit<int>::Max())

        {

            return NULL;

        }

 

        int nConverted = WideCharToMultiByte(

            CP_UTF8,

            0,

            lpszWideString,

            (int)(nWideCharCount),

            lpszUTF8String,

            (int)(nUTF8ByteCount),

            NULL,

            NULL);

 

        if(nConverted == 0 && ERROR_NO_UNICODE_TRANSLATION == GetLastError())

        {

            return NULL;

        }

 

        lpszUTF8String[nConverted] = '/0';

        return lpszUTF8String;

    }

 

【实战】基于 Inner-IoU 的 YOLOv8 优化指南:显著提升检测精度 Inner-IoU 凭借辅助边框的创新设计,成功解决了传统 IoU 损失在小目标、遮挡场景下的收敛难题,为 YOLOv8 注入了更强的定位能力。从原理剖析到代码集成,本教程已为你铺就了一条“精度提升”的实战路径。现在,不妨亲自上手尝试,让你的目标检测模型在各类数据集上都能交出一份“精度优异”的答卷——相信我,当你看到检测框精准贴合目标的那一刻,你会明白这份尝试的价值。 阅读详情

相关推荐

一文读懂GAN, pix2pix, CycleGAN和pix2pixHD

本文翻译、总结自朱俊伟的线上报告,主要讲了如何用机器学习生成图片。 来源:Games2018 Webinar 64期 :Siggraph 2018优秀博士论文报告 人员信息 主讲嘉宾 姓名:朱俊彦(Jun-Yan Zhu) 现状:麻省理工学院博士后(PostDoc at MIT),计算机科学与人工智能实验室(Computer Science and Artificial In...

gdymind的博客 6万+

VC9中ATL的atlconv.h中A2W_CP和W2A_CP的Bug

 VC9中ATL的atlconv.h有Bug,请大家注意一下,这些问题网上也能搜索到:http://blog.youkuaiyun.com/BalonFan/archive/2009/04/24/4108985.aspx,但它对EX系列的转换宏理解错了。我这里澄清一下:W2A_CP转换宏,allocate分配的空间大小不对(它原来只固定乘2),但当cp为UTF8时,是有可能一个汉字转换

冰峰 的专栏 5710

16QAM调制解调仿真(matlab,详细介绍仿真方案的设计、结果及结论、完整代码及注释)

16QAM调制解调仿真目录一、仿真要求二、仿真方案详细设计三、仿真结果及结论四、仿真代码 一、仿真要求 1.用基带等效的方式仿真16-QAM在AWGN信道下的误码率和误比特率性能,并与理论值相比较; 2.高阶与低阶的性能比较。 二、仿真方案详细设计 三、仿真结果及结论 仿真结果 16QAM的星座点图 64QAM的星座点图 16QAM加噪声后的星座点图 64QAM加噪声后的星座点图 16-QAM载波调制信号在AWGN信道下的误比特率性能比较 结论:由图可知,16QAM的误符号率

mango 5万+

关于A2W字符转换宏

在一个函数的循环体中使用A2W等字符转换宏可能引起栈溢出。#include void fn(){    while(true)    {        {            USES_CONVERSION;            DoSomething(A2W("SomeString"));        }    }}让我们来分析以上的转换宏#define A2W(lpa) (/

jia_xiaoxin的专栏 1659

simulink求解器选择的小tip

给出了simulink选择求解器的一种tip,与积分初值有关。

高能阿博特的博客 2054

多IMU车载GNSS/INS数据集及介绍

文章目录前言非常棒的GINS数据集采集轨迹采集时间MEMS IMU详细信息IMU测量值方程及相关误差建模参考噪声参数安装参数文件格式描述 前言 “本文作者感谢武汉大学多源智能导航实验室和牛小骥教授提供了本文所需的GNSS/INS数据集。” 本博文介绍数据集链接为多IMU车载GNSS、INS数据集,欢迎大家下载,由于是开源数据集,因此下载不需要积分 非常棒的GINS数据集 这是一套非常好的用于GNSS/INS组合导航应用的车载数据集,本数据集采集于湖北省武汉市一处工业园区,为开阔天空场景,GNSS R

十八与她的博客 6440

USES_CONVERSION的相关宏A2W、W2A使用注意事项

有一天发现,这个多字节和unicode编码转换有了 USES_CONVERSION、A2W、W2A 几个宏后,简单了很多,用起来也方便的很。 以前有注意到,说 A2W、W2A 的“返回值”不用删除,它自己回收,立即感觉这个相当好,都不用管内存的分配和删除了,用完弃之即可。 如今涉及到这个问题,不得不面对。几乎花了半天的功夫终于弄清楚是啥情况了。先说问题。 MFC程序,有一个CListCtrl...

jszj的专栏 2093

Argoverse2数据集保姆级导入教程:从下载到预处理全流程解析

本文详细解析了Argoverse2数据集的完整导入流程,从环境配置、数据下载到预处理和高效加载策略。作为自动驾驶领域的标杆数据集,Argoverse2提供多模态传感器数据和高精地图信息,帮助研究者快速搭建数据处理流水线。文章包含实用代码示例和性能优化技巧,特别适合自动驾驶算法开发者参考。

weixin_29035405的博客 336

UTF-8编解码之实现

根据对UTF8编码格式的研究,作出如下的简单的实现代码,希望大家指正批评并继续完善:int WideCharToUTF8(wchar_t* source, int sourceLen, unsigned char* dest, int& destLen)...{ destLen = 0; if (sourceLen  0) ...{  return destLen = 0; } wchar

winner82的专栏 1186

手把手教你学simulink(40.1)--水力发电场景示例:基于 Simulink 的抽水蓄能电站水力发电

项目背景抽水蓄能电站是一种重要的储能技术,广泛应用于电力系统的调峰填谷、频率调节和备用电源。它通过在电力负荷低谷时将水从下水库抽到上水库储存,在电力负荷高峰时释放水进行发电,从而实现电能的高效利用。与传统的水电站不同,抽水蓄能电站可以在短时间内快速响应电网的需求,具有良好的灵活性和可靠性。本项目旨在使用 MATLAB/Simulink 模拟一个完整的抽水蓄能电站的水力发电过程,包括水泵-涡轮机系统、发电机、水道系统、控制系统等,并实现对电站的精确控制,确保其在不同工况下都能稳定运行。

MHD0815的博客 886

网络流量异常信息分析方法研究

本课题针对网络安全中网络流量异常的分析方法进行研究,提出一种基于机器学习和深度学习的异常检测算法。该算法采用卷积神经网络(CNN)和长短时记忆神经网络(LSTM)结合的方式,通过训练得到二分类模型,从而实现对网络流量异常的检测。随着互联网的飞速发展,网络攻击事件日益增多,网络安全问题成为了亟待解决的问题之一。常见的网络攻击手段包括 DDoS 攻击、SQL 注入、XSS 攻击等,这些攻击手段可能导致网络系统发生异常,给网络运维、数据安全带来极大的挑战。

肥晨开发的学习之路 1035

使用ATL的W2A和A2W宏

#include 代码如下://使用ATL的W2A和A2W宏必须使用USES_CONVERSIONUSES_CONVERSION; //Unicode字符串wchar_t* wszText=L"1.Unicode字符转换为ANSI;";printf("%s/n",W2A(wszText)); //用wprintf输出非英文字符,需要设置当前的地域信息setlocal

生命因你而精彩!明天更美好! 1660

整理 钢琴 铃木钢琴教程(铃木)

铃木钢琴 超清PDF

TS的博客 1213

ATL的另一个陷阱

ATL早期提供了宏A2W,W2A进行编码转换,但是该组宏存在以下缺点: 1、默认认为转换前的参数(A2W)、转换后的结果(W2A)的编码是ANSI; 2、转换后结果保存在栈上。   该组宏无法满足我们从UTF8、UCS2之间的互相转换,并且有可能导致栈溢出。鉴于此,当我发

lyclowlevel的专栏 1848

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

C++/MFC Unicode 串口开发避坑指南:3步解决字符集转换与数据解析乱码

本文深入探讨了C++/MFC在Unicode环境下进行串口开发时遇到的字符集转换与数据解析乱码问题,提供了3步解决方案。通过Win32 API和ATL转换宏的安全使用,以及二进制数据处理的正确方法,帮助开发者有效避免常见陷阱,特别适用于工业控制和光源控制器等场景。

weixin_34074740的博客 491

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

UTF8转换宏和转换类

参考微软 ANSI和WCHAR的转换代码,编写的UTF8和ANSI、WCHAR转换代码。 可在ATL/MFC环境下使用。

crazy Crypto 3547

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

A2W W2A A2T T2A _T() 含义以及用法

A2W、W2A、A2T、T2A _T() 的含义及使用方法 1、A2W和W2A 在《Window核心编程》,多字节和宽字节之间转换比较麻烦的,MultiByteToWideChar函数和WideCharToMultiByte函数有足够多的参数的意义让我们去理解。那么使用ATL的一个很好的字符串的转换宏:A2W和W2A。 char:8位字节类型,表示ASCII码 WCHAR:16位字符类型,表示Un...

流楚丶格念的博客 6633

UTF-8 与UniCode 编码转换

 所谓“utf-8”只是UCS Transformation Format,只是UNICODE的一种表现形式,不等同于UNICODE,一般汉字在UNICODE中为两个(双)字节表示,而我们看到实际保存的文档确是三个字节表示一个汉字的,看看下表:U-00000000 - U-0000007F:  0xxxxxxxU-00000080 - U-000007FF:  110xxxxx 10xxx

提升自己-虚心钻研 1414

UNICODE与UTF-8的转换

3.3 UTF-8的编码方式 UTF-8是UNICODE的一种变长度的编码表达方式(一般UNICODE为双字节[指UCS2]),UTF-8就是以8位为单元对UCS进行编码,而UTF-8不使用大尾序和小尾序的形式,每个使用UTF-8储存的字符,除了第一个字节外,其余字节的头两个位元都是以"10"开始,使文字处理器能够较快地找出每个字符的开始位置。 为了与以前的ASCII码相容(ASCII为一个字节),因此 UTF-8 选择了使用可变长度字节来储存 Unicode,具体转换关...

满腹的小不甘 1万+

UTF8和UNICODE互转

/* * ===================================================================================== * * Filename: iconv.c * * Description: j * * Version: 1.0 * Created: 08/05...

CJJ的专栏 408

BIG5编码, GB编码(GB2312, GBK, ...), Unicode编码, UTF8, WideChar, MultiByte, Char 说明与区别

一. BIG5编码, GB编码(GB2312, GBK, ...), Unicode编码 1.1. BIG5编码 BIG5字集是台湾繁体字集,共包括国标繁体汉字13053个 1.2. GB编码 GB2312字集是简体字集, 全称为GB2312(80)字集, 共包括国标简体汉字6763个; GB2312是中国规定的汉字编码, 也可以说是简体中文的字符集编码; GBK包含全部中文字

cay22的专栏 1万+

A2W和W2A 很好的多字节和宽字节字符串的转换宏

A2W和W2A 很好的多字节和宽字节字符串的转换宏

gdruhv的博客 5209

【VS开发】GDI+ 用CImage类来显示PNG、JPG等图片

系统环境:Windows 7 软件环境:Visual Studio 2008 SP1 本次目的:实现VC单文档、对话框程序显示图片效果 CImage是VC.NET中定义的一种MFC/ATL共享类,也是ATL的一种工具类,它提供增强型的(DDB和DIB)位图支持,可以装入、显示、...

weixin_30344995的博客 607

ATL字符串转换类

字符串的ASCII和UNICODE之间的转换很常用,Win32提供了API函数MultiByteToWideChar和WideCharToMultiByte来提供这种功能。但凡Win32的API,参数调用都不会少,因此使用起来也就觉得有点繁琐。ATL3中提供了字符串转换宏,如T2W、A2T等,不过使用它们需要借助本地变量,因此在使用之前需要声明USES_CONVERSION宏来声明本地变量.而且还...

weixin_30354675的博客 350
上一篇: 运行期显示多态指针的类型名
下一篇: 条件断点引发的血案
BalonFan
博客等级 码龄26年 47粉丝 41原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值