DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: forget66
今日帖子: 60
在线用户: 16
导航: 论坛 -> 文档资料 斑竹:liumazi,ruralboy  
作者:
男 lzj7015 (lzj) ★☆☆☆☆ -
普通会员
2017/3/26 11:37:25
标题:
抛砖引玉,新版CB缺陷的解决方法 浏览:10292
加入我的收藏
楼主: 新版C++Builder 10.2,若编译64位程序,嵌入而非链接运行时库,调用显示对话框相关函数时,对话框标题、按钮标题显示为乱码,寻到了两个解决方法。
1、调用MessageBox函数。新版CB的String类,可以使用前导字符“L”显式指明WideChar类字符串,具较大实用价值。代码如下:
String testStr = L"需付" + IntToStr(12) + L"元";
Application->MessageBox(testStr.c_str(), L"信息", MB_OK);

2、将Vcl.Dialogs.pas单元文件引入CB项目,修改这个文件,添加的代码始于6120行,修改的代码始于6236行、6283行,详情参见附件。
希望后出的CB能消除这一缺陷。

我现在常用QT进行高并发数据分析开发,CB用得少,只要掌握了C++,CB上手很快。一位年轻朋友,从未接触过CB,因项目所需,仅只1星期,使用CB圆满完成任务。
此帖子包含附件:lzj7015_2017326113725.rar 大小:36.1K
----------------------------------------------
-
作者:
男 hhjj3388 (谁杀了我的牛) ▲▲▲▲△ -
普通会员
2017/3/26 12:21:27
1楼: Qt  做什么方面的高并发 数据分析呢?
----------------------------------------------
-
作者:
男 nevergrief (孤独骑士) ★☆☆☆☆ -
盒子活跃会员
2017/3/26 20:26:37
2楼: 什么叫做“嵌入而非链接运行时库”?以前版本的CB有这个问题吗?
----------------------------------------------
只有偏执狂才能生存!
作者:
男 liyanhong (李彦宏) ▲▲▲▲△ -
普通会员
2017/3/27 11:13:26
3楼: 有几点疑问:
1:你的源文件是用GBK、GB18030、UTF-8还是UTF-16LE编码?如果是UTF-8可能就会出现乱码。我没有试过,我觉得应该是这个问题。这是源文件编码。还有一个运行时编码。你看看,你在字符串前加了前缀L,这就保证了运行时编码是UTF-16LE。总而言之,字符串有两个编码转换过程:源文件编码--->运行时编码--->界面编码。
2:“嵌入而非链接运行时库”,应该是静态链接和动态链接。
----------------------------------------------
-
作者:
男 lzj7015 (lzj) ★☆☆☆☆ -
普通会员
2017/3/27 12:41:02
4楼: 一并作答。
现今所从事的数据分析开发工作,主要服务于某大型购物网站,也常使用Python进行开发。
较高版本的CB的IDE打开或创建相关文件时使用的是utf8编码,CB的String类编码为Unicode,即便使用形如 String str = u8"𥁐" 显式指明为utf8编码,编译后依然是Unicode编码,所以上述代码中字符串不能正确显示,需另外的解决方法。这显然与C++11规范相逆,C++11中规定,utf8编码应能表示全世界所有民族的所有字符。
以前版本的CB没有这个问题。C++Builder10.2之所以会出现显示乱码的问题,据我推测,是由于64位delphi编译器编译单元文件时,所调用的32位资源编译器生成了CB 64位编译器未能正确识别的字符串。C++Builder10.2的String类可以使用“L”显式指明WideChar类的字符串,是为了开发者更方便调用Windows底层函数,而这又可能是导致C++Builder10.2显示乱码的原因。后出的CB应能解决这个问题。
3楼所言的“字符串有两个编码转换过程:源文件编码--->运行时编码--->界面编码。”确切含义不明。
----------------------------------------------
-
作者:
男 liyanhong (李彦宏) ▲▲▲▲△ -
普通会员
2017/3/27 14:58:36
5楼: 以gcc为例,它有三个命令选项:
-finput-charset=gb18030
-fexec-charset=utf-8
-fwide-exec-charset=utf32
顾名思议,input-charset指的是源文件中字符串常量(字面量)的编码,exec-charset是运行时字符编码,也就是可执行文件中的字符串编码,wide-exec-charset是运行时宽字符编码。
还有一个编码,就是本地字符串编码,这个需要在程序启动时通过setlocale函数指定。
显然,从gb18030到utf-8,需要一个转码过程,这个就是源文件编码---->运行时编码;从gb18030到utf32的转换也是源文件编码---->运行时编码。这是编译时完成的。
从运行时编码到本地字符串编码的转换,发生在运行时,程序需要展示信息时。本地编码对界面和控制台是否出现乱码有影响。
VC++从2015 update 3 开始,也有相应的命令行选项:
-execution-charset:gb18030
-source-charset:gb2312
c++ builder里的clang或bcc虽然没有相应的命令行选项,但是一定有上面提到的转换过程,只不过编码是默认的。
----------------------------------------------
-
作者:
男 liyanhong (李彦宏) ▲▲▲▲△ -
普通会员
2017/3/27 15:10:16
6楼: String str = u8"𥁐"显式指明为utf8编码,编译后依然是Unicode编码,是不是 String类的构造函数作了编码转码?试试 const char *str = u8"𥁐",看看 str 是什么编码的?
----------------------------------------------
-
作者:
男 lzj7015 (lzj) ★☆☆☆☆ -
普通会员
2017/3/27 17:10:51
7楼:   在大多数情况下,勿需如5楼所言,指明不同情形下所采用的编码,   原因如下:
1、现在已知的通行的各类明码文档,皆在文件头部带有文档编码信息;  主流开发语言的主流开发框架所提供的相关部件,打开、创建明码文件时,也提供了读取文件编码信息、依据此信息进行解析的功能。
2、主流开发语言的主流编译器所提供资源编译功能,在编译字符串后,也都保留了相应的编码信息,相关部件也能获取此信息,解析后正确显示,如菜单标题等。
----------------------------------------------
-
作者:
男 liyanhong (李彦宏) ▲▲▲▲△ -
普通会员
2017/3/27 18:19:36
8楼: 1、这里的明码文档是什么文档?xml文档吗?我说的是C/C++源文件中,字符串字面量的编码,就是
String testStr = L"需付" + IntToStr(12) + L"元";
Application->MessageBox(testStr.c_str(), L"信息", MB_OK);
这样的代码中,汉字字符串的编码。汉字字符串在源文件中的编码是在IDE(VC/CB)的编辑器中指定的,像L和u8这样的前缀,指明的是运行时的编码,是定义在语言标准中的。“文件头部带有文档编码信息”,应该是指BOM吧?如果编译器不能识别源文件的编码,就会在编译时或运行时出错。

之所以不用关心,是因为大多数情况下,编辑器的编码是utf-8、gbk或utf-16le。这些编码可以被编译器识别。就算是utf-8、utf-16le,也有不带BOM的情况。gbk文件根本就没有BOM。

简单总结一下:
1.gcc、clang 对 utf-8的支持:有无 BOM 均可,都不支持 utf-16le
2.cl 需要 BOM 才能正确支持 utf-8 和 utf-16
3.cl 正确支持 gb18030
4.gcc 用 -finput-charset 指定源文件编码(非utf-8)后,才能正确把源文中的宽字
  符串编码转为 utf-16le
5.clang 不支持 gb18030 源文件编码

带BOM的utf-8编码的源文件,通行天下。

VC和Qt Creator 都有设置源文件编码的选项,而且,notepad、emacs、vim也都可以设置源文件编码。

至于C/C++以外的其它主流开发语言,基本上都只认utf-8编码的源文件,它们对unicode的支持,都是以utf-8为基础的。你可以看一下你的IDE的设置,如果是utf-8,把它改成gbk试试。

2、“主流编译器所提供资源编译功能”中,什么是资源编译功能?是指的类似于VC++里的rc.exe和mingw中的winres.exe这样的资源编译器吗?还是指QT自己的资源编译器?如果说它们保留了字符串编码信息,这是对的,因为它们对.rc文件的编码不作转码。“解析后正确显示,如菜单标题等”的前提是,.rc文件的编码必须正确。

至于开发出来的应用程序处理的数据的编码,那就和编译器没有关系了。
----------------------------------------------
-
作者:
男 liyanhong (李彦宏) ▲▲▲▲△ -
普通会员
2017/3/27 19:33:32
9楼: 你用Qt用的多,我来给你说一下怎么在Qt中重现汉字乱码。
环境:
1:VC++2015 update 3
2:Qt 5.8.0 64 bit
操作:
1:启动 Qt Creator;
2:把Qt Creator的源文件编码改为gb18030;在[工具]-[选项]-[文本编辑器]里,
找[行为]标签,可以在右侧看到默认编码,把它改为gb18030;
3:新建一个 Qt Widget Application;
4:在MainWindow的构造函数里添上这么一行:
new QPushButton("你好", this);
5:编译运行;
6:可以看到界面上出现了乱码。
解决方法,任选一:
1:不改源文件编码,把代码改为:
new QPushButton(QStringLiteral(u"你好"));
2:改源文件编码为utf-8,不改代码。
----------------------------------------------
-
作者:
男 lzj7015 (lzj) ★☆☆☆☆ -
普通会员
2017/3/27 19:48:12
10楼:      明码文件,是指文件内容为采用某种编码格式的字符串,诸如txt、cpp、xml、pas   等文件,这些文件都存有相关的编码信息,比如常用的txt文件,可以采用很多编码格式,无相关的编码信息,无法正确显示。BOM,是指采用utf8进行编码、且在文件尾部留有特殊信息的一种明码文件格式,现今大多数C/C++源文件建议采用这种格式。

我想说的是,编译C/C++源文件,大多数情况下勿需指定各种情形下所采用的编码格式。至于在代码中指明字符串编码、源文件的编码,我在上面的回答中已有叙述。
精力不济,对这个问题的讨论到此为止,请见谅。
----------------------------------------------
-
作者:
男 liyanhong (李彦宏) ▲▲▲▲△ -
普通会员
2017/3/27 21:01:24
11楼: 在代码中,指明源文件的编码是不可能的。也就是说,在代码中,不可能指明.c、.cxx、.h、.cpp等文本形式存在的“源”文件的编码。

在代码中,可以指定.exe文中字符串的编码,这个时候的编码是运行时编码。

BOM全称Byte Order Mark,utf-8的BOM是0xEF,0xBB,0xBF,utf-16le的BOM是0xFF,0xFE,utf-16be的BOM是0xFE,0xFF。utf-32le、utf-32be、utf-7等也有BOM。

BOM不只是utf-8有。BOM只出现在文本的开始处,没有听说过在结尾处还有“留有特殊信息的”的情况。如果你知道,还请不吝赐教。

“诸如txt、cpp、xml、pas   等文件,这些文件都存有相关的编码信息”,还想请教一下,这里说的“相关的编码信息”,是用什么形式保存的什么信息?是编码本身吗?因为我没有发现文件的大小因为“存有相关的编码信息”而增加。
----------------------------------------------
-
作者:
男 hyz_hz (随风) ★☆☆☆☆ -
普通会员
2017/3/28 10:40:36
12楼: 字符串前面加L就可以了, 并不是10.2开始才这样的,你有用过之前的,10.1,10.0还有之前的XE系列吗?
----------------------------------------------
-
作者:
男 liyanhong (李彦宏) ▲▲▲▲△ -
普通会员
2017/3/28 11:23:12
13楼: 楼主说的是这样的乱码:
void __fastcall TForm1::Button3Click(TObject *Sender)
{
  String  testStr = L"需付" + IntToStr(12) + L"元";
  MessageDlg(testStr, mtInformation, mbAbortRetryIgnore, 0);
}
64 位,静态链接,VCL form Application。32位的和动态链接的,我没有实验。
此帖子包含附件:
PNG 图像
大小:10.5K
----------------------------------------------
-
作者:
男 liyanhong (李彦宏) ▲▲▲▲△ -
普通会员
2017/3/28 14:04:33
14楼: “C++11中规定,utf8编码应能表示全世界所有民族的所有字符”,C+11中没有这样的规定,C++的标准(在C++11之前已经存在,并且在C++11中没有更改)中说,wchar_t Required to be large enough to represent any supported character code point (32 bits on systems that support Unicode. A notable exception is Windows, where wchar_t is 16 bits and holds UTF-16 code units) It has the same size, signedness, and alignment as one of the integral types, but is a distinct type. 我们一般理解为,wchar_t是一个特定编译器在一个特定系统中用来表示所有(所有民族)字符的最大字符类型。这个wchar_t类型 ,在Linux上是4个字节大小,采用的是utf-32编码,在windows上是2个字节大小,采用的是utf-16编码。

下面这才是C++11新增的数据类型:
    char16_t - type for UTF-16 character representation, required to be large enough to represent any UTF-16 code unit (16 bits). It has the same size, signedness, and alignment as std::uint_least16_t, but is a distinct type. 
    char32_t - type for UTF-32 character representation, required to be large enough to represent any UTF-32 code unit (32 bits). It has the same size, signedness, and alignment as std::uint_least32_t, but is a distinct type. 

char16_t的字面量,加前缀u;
char32_t的字面量,加前缀U;

这里还是没有utf-8什么事。下面才是utf-8的。

C++11中只增加了一种表示utf-8编码的字面量的方法,就是加前缀u8。


你可以看看标准文档啊,里面根本就没有说,utf8编码应能表示全世界所有民族的所有字符,如果说了,说的也是wchar_t类型,实践中通常用utf-32和utf-16编码。
----------------------------------------------
-
作者:
男 liyanhong (李彦宏) ▲▲▲▲△ -
普通会员
2017/3/28 14:33:50
15楼: function LoadResString(ResStringRec: PResStringRec): string;
var
  Buffer: array [0..4095] of Char;
begin
  if ResStringRec = nil then Exit;
  if ResStringRec.Identifier < 64*1024 then
    SetString(Result, Buffer,
      LoadString(FindResourceHInstance(ResStringRec.Module^),
        ResStringRec.Identifier, Buffer, Length(Buffer)))
  else
    Result := PChar(ResStringRec.Identifier);
end;

关于楼主的问题,我用delphi 32位、64位、C++Builder 32位,都用静态链接,跟踪了一下程序的执行,发现执行到上面这个函数时,ResStringRec.Identifier都是小于64KB的。

到了C++ Builder 64位静态VCL程序中,我只能跟踪到这里:
  String __fastcall LoadResourceString(ResourceString const * const rsrc)
  {
    return System::LoadResString(const_cast<TResStringRec*>(rsrc));
  }

在Local Variables窗口中可以看到,rsrc->Identifier已经大于64KB了,这可能是个错误。我不了解Delphi 的pascal编译器是怎么初始化Identifier的,但是我觉得这个Identifier的值应该是错的。

rsrc->Identifier大于64KB时,就不从资源中取字符串了,而是直接这样了:

Result := PChar(ResStringRec.Identifier);

这里应该是非法访问吧?
----------------------------------------------
-
作者:
男 liyanhong (李彦宏) ▲▲▲▲△ -
普通会员
2017/3/28 14:40:56
16楼: 先包含头文件:#include <Vcl.Consts.hpp>

void __fastcall TForm1::Button4Click(TObject *Sender)
{
  const wchar_t *str0 = Vcl_Consts_SMsgDlgYes.c_str();

  TResStringRec rec = Vcl::Consts::_SMsgDlgYes;
  const wchar_t *str1 = (const wchar_t *)rec.Identifier;
}

执行后可以发现,str0和str1的内容是一样的。这样就更说明了,这个乱码的出现和资源没有关系,更像是新版bcc64的BUG。

我也不再纠结这个问题了,就此打住。
----------------------------------------------
-
作者:
男 liyanhong (李彦宏) ▲▲▲▲△ -
普通会员
2017/3/28 16:43:09
17楼: 看来我判断错了,来纠正一下,看图吧:
此帖子包含附件:
PNG 图像
大小:71.2K
----------------------------------------------
-
作者:
男 liyanhong (李彦宏) ▲▲▲▲△ -
普通会员
2017/4/2 15:40:38
18楼: 楼主那哥们,你脑子里那么多自以为是、先入为主、似是而非的概念是怎么形成的?
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行156.25毫秒 RSS