【问题标题】:Understanding Multibyte/Unicode了解多字节/Unicode
【发布时间】:2017-05-30 18:49:43
【问题描述】:

我刚刚回到编程 C++、MFC、Unicode。过去 20 年发生了很多变化。

另一个项目上的代码编译得很好,但是当我将它粘贴到我的代码中时出现错误。我花了 1-1/2 天的时间来解决下面的函数调用:

enter code here
CString CFileOperation::ChangeFileName(CString sFileName)
{
  char drive[MAX_PATH], dir[MAX_PATH], name[MAX_PATH], ext[MAX_PATH];
  _splitpath_s(sFileName, drive, dir, name, ext);  //error
  ------- other code
}

阅读帮助后,我将 CString sFileName 更改为使用强制转换:

enter code here
_splitpath_s((LPTCSTR)sFileName, drive, dir, name, ext);  //error

这也造成了错误。于是我用了GetBuffer(),和上面的完全一样。

enter code here
char* s = sFileName.GetBuffer(300);
_splitpath_s(s, drive, dir, name, ext);  //same error for the 3rd time
sFileName.ReleaseBuffer();

此时我非常沮丧,但最终意识到我需要将 CString 更改为 Ascii(我想是因为我设置为 Unicode)。

因此;

enter code here
CT2A strAscii(sFileName);   //convert CString to ascii, for splitpath()

然后在函数_splitpath_s()中使用strAscii.m_pz

这终于奏效了。因此,在这一切之后,长话短说,我需要帮助专注于: 1. Unicode vs Mulit-Byte(库调用) 2. 变量使用

我愿意再买一本书,请推荐。 另外,有没有办法过滤我对 VS2015 的帮助,这样当我在一个变量上并按 F1 时,它只会为我提供 Unicode 的帮助以及将旧代码转换为 unicode 或将 Mylti-Byte 转换为 Unicode 的方法。

希望这不会令人困惑,但我还有一些事情要做。如果我的措辞不完美,请耐心等待。

提前致谢。

【问题讨论】:

  • 请重新阅读stackoverflow.com/tour... SO 是针对具体的编程问题,任何类型的建议都是题外话。作为旁注:选择其他语言(即 C#,因为您已经在使用 VS)或至少更现代的 C++ 库将使查找帮助变得更加容易......
  • 在过去的 20 年里发生了很多变化。 .. 是的,更深奥的方法会导致缓冲区溢出 :)
  • 从这里开始:unicode.org/standard/principles.html 注意“代码点”以及将它们编码为多字节的 UTF-X 方式。
  • 顺便说一句,GetBuffer() 是错误的成员函数,如果您只需要一个指向字符串对象的非可变缓冲区的指针。你应该改用CString::GetString()
  • 谢谢;我不知道 GetString() 存在(因为它当时不存在)。我已经阅读了一些关于它的内容,并看到它是在中实现的

标签: c++ unicode macros mfc


【解决方案1】:

documentation of _splitpath 列出了 Unicode(基于wchar_t)版本_wsplitpath。那是你应该使用的那个。不要转换为 ASCII 或 Windows ANSI,这通常会丢失信息,并且在重新组合片段时不会生成有效路径。

现代 Windows 编程基于 Unicode。

默认情况下,Visual Studio C++ 项目是基于 Unicode 的,特别是它定义了宏符号 UNICODE,它会影响来自 <windows.h> 的声明。

【讨论】:

  • 基于 Unicode 的项目还定义了控制 CRT 的通用文本映射的 _UNICODE 预处理器符号。但是,如果您调用显式 Unicode 版本的函数调用(正如您在此答案中所建议的那样),则 UNICODE_UNICODE 符号都不是必需的。
  • 嗯,我不建议通常明确地使用...W 形式的 API 函数。正如我所看到的,没有这些,代码变得更具可读性。例如。我只写MessageBox,而不是MessageBoxW。但我不熟悉_wsplitpath 的任何无前缀形式。写。运行时库的_UNICODE,值得注意的是CRT 的东西在three encodings 之间有区别,而不仅仅是<windows.h> 的两个:对于CRT,还有_MBCS,如果我没记错的话。同时定义_MBCS_UNICODE 会出错。
  • 使用_wsplitpath(与_tsplitpath)的建议相当不一致,但MessageBox(与MessageBoxW相比)。建议不要使用TCHARs(这很好),没有容易想象的理由,但请继续为 Windows API 调用使用通用文本映射。
  • @IInspectable:旧用途(通用文本映射)对于使用简单记录的 API 函数名称无关紧要。在某些情况下,即使使用 Microsoft 自己的代码,大量的宏也会令人烦恼并造成严重破坏。但无论如何都无法避免:没有办法告诉<windows.h> 不定义宏。如果有的话,那么我会倾向于三思而后行,或者更多地考虑不同意你的观点。 ;-)
  • “宏的数量异常令人烦恼” - 这就是您建议继续使用它们的原因吗?没有可理解的好处? “但无论如何也无法避免:没有办法告诉<windows.h> 不定义宏。” - 但是有#undef,所以你可以拥有无​​宏代码,如果你足够关心。好吧,当然不是你,因为你决定编写依赖于它们烦人的宏的代码。顺便说一句,为什么?
【解决方案2】:

所有受支持的 Windows 版本自始至终都在内部使用 Unicode,您的应用程序也应该如此。 Windows 使用UTF-16 编码。

要使您的应用程序支持 Unicode,您需要执行以下步骤:

  • 将项目的Character Set 设置为“使用 Unicode 字符集”(如果当前设置为“使用多字节字符集”)。这不是严格要求的,但它可以处理那些您没有明确使用 Unicode 版本的情况。
  • 使用wchar_t(代替charTCHAR)作为您的字符串。
  • 使用宽字符串文字(L"..." 代替 "...")。
  • 在 MFC 项目中使用 CStringW(代替 CStringACString)。
  • 显式调用 CRT 的 Unicode 版本(例如,wcslen 代替 strlen_tcslen)。
  • 显式调用任何存在的 Windows API 调用的 Unicode 版本(例如,CreateWindowExW 代替 CreateWindowExACreateWindowEx)。

【讨论】:

  • 添加那些W 后缀只会降低代码的可读性。就像微软的Hungarian notation。只是不必要的负值冗长。所以这是个坏建议。其余大部分都很好。 :)
  • @Cheersandhth.-Alf:那些盲目批评匈牙利符号的人通常没有掌握它。我邀请您下载并查看Microsoft Word 1.1a 的源代码。另外,从您的(自以为是的)链接:“反对匈牙利表示法的大多数论据都反对 *Systems 匈牙利表示法,而不是 Apps 匈牙利表示法。”*
【解决方案3】:

尝试使用_tsplitpath_sTCHAR

所以最终的代码看起来像:

CString CFileOperation::ChangeFileName(CString sFileName)
{
  TCHAR drive[MAX_PATH], dir[MAX_PATH], name[MAX_PATH], ext[MAX_PATH];
  _tsplitpath_s(sFileName, drive, dir, name, ext);  //error
  ------- other code
}

这将使 C++ 编译器能够在构建期间根据项目设置使用正确的字符宽度

【讨论】:

  • Windows 9x 兼容性宏已超过“使用前”日期 20 年。在我看来,尝试支持编译器无法为其生成可执行文件的 Windows 版本比没有意义更糟糕。
猜你喜欢
  • 2011-01-14
  • 2013-01-22
  • 2023-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多