Delphi 10.3函数CharUpper和CharUpper与Delphi 10.4不同

Delphi 10.3函数CharUpper和CharUpper与Delphi 10.4不同,delphi,Delphi,有人知道Delphi10.3中的CharUpper和CharUpper声明与Delphi10.4中的声明不同的原因吗 Delphi10.3中的正确声明 var chr :WideChar; begin chr := WideChar(CharUpperW(PWideChar('a'))); //chr = 'A' // chr := WideChar(CharUpperW(WideChar('a'))); //raise exept

有人知道Delphi10.3中的
CharUpper
CharUpper
声明与Delphi10.4中的声明不同的原因吗

Delphi10.3中的正确声明

    var
      chr   :WideChar;
    begin      
      chr := WideChar(CharUpperW(PWideChar('a'))); //chr = 'A'
//    chr := WideChar(CharUpperW(WideChar('a')));  //raise exeption: "access violation...
Delphi10.4中的正确声明

    var
      chr   :WideChar;
    begin   
//    chr := WideChar(CharUpperW(PWideChar('a')));  //raise exeption: "access violation...
      chr := WideChar(CharUpperW(WideChar('a')));   //chr = 'A'
编辑:Remy Lebeau对PWideChar的解释是正确的,但Delphi 10.4版和早期版本仍然存在差异

Lebeau expalation代码示例在版本10.4和早期版本中编译,但函数的输出不同。10.4之前的所有版本都获得了正确的输出“A”

10.4下的此示例无法更正输出为随机字符

当然。。。 函数的声明在Delphi的boath版本中是相同的

LPWSTR = PWideChar; 
function CharUpperW(lpsz: LPWSTR): LPWSTR; stdcall;**
编辑:在10.4中添加反汇编代码

umCommon.pas.114: chr := 'a';
0064C52C 66BB6100         mov bx,$0061
umCommon.pas.115: char := WideChar(CharUpperW(PWideChar(chr)));
0064C530 8D45FC           lea eax,[ebp-$04]
0064C533 8BD3             mov edx,ebx
0064C535 E8EEE7DBFF       call @UStrFromWChar
0064C53A 8B45FC           mov eax,[ebp-$04]
0064C53D E8C2E7DBFF       call @UStrToPWChar
0064C542 50               push eax
0064C543 E8809DDCFF       call CharUpperW
10.3下的反汇编代码

umCommon.pas.114: chr := 'a';
0063A905 66BB6100         mov bx,$0061
umCommon.pas.115: char := WideChar(CharUpperW(PWideChar(chr)));
0063A909 0FB7C3           movzx eax,bx
0063A90C 50               push eax
0063A90D E8AAB1DDFF       call CharUpperW
Win32
CharUpperW()
函数不接受单个
WideChar
作为输入,只接受一个
PWideChar
。但该指针的解释取决于其高阶字是零(低阶字包含一个字符)还是非零(整个指针指向以null结尾的字符串)

CharUpperW(WideChar('a'))
甚至可以在任何版本中编译的唯一方法是,Embarcadero添加了自己的重载,将单个
WideChar
作为输入(我没有安装任何10.x版本来验证)

总之,
CharUpperW()
使用起来有点危险,因为指针被滥用了。对于类型转换的文本,我不相信它,而是使用变量,这样您可以确保您给出的正是它真正想要的:

var
chr:WideChar的数组[0..1];
开始
chr[0]:=“a”;
chr[1]:=#0;
查沃(chr);
结束;
var
chr:WideChar;
开始
chr:='a';
char:=WideChar(CharUpperW(PWideChar(chr));
结束;
也就是说,RTL中还有其他函数来处理此任务,请改用这些函数

更新:我已为此创建了支持票证:


由于Delphi 10.4创建隐藏字符串,并且当它与单个字符或以null结尾的字符串输入一起工作时,
charupper w
会起作用,因此您需要重写代码,使其与10.4和10.3(及更早版本)的代码保持一致:

var
  s: string;
begin
  s := 'a';
  CharUpperW(@s[1]);
end;


另外,由于这些困难,我建议您使用System.SysUtils中的
大写
/
AnsiUpperCase

好的,在您的帮助下,我找到了答案。。。 实际上,函数
CharUpper
CharUpperW
位于
Winapi.Windows
单元中,它们都调用相同的API调用
CharUpperW
。 但是在Delphi 10.4版的unit
Winapi.Windows
中出现了新的函数重载:

function CharUpper(lpsz: LPWSTR): LPWSTR; overload; stdcall; external user32kernel name 'CharUpperW';
function CharUpper(tch: WideChar): WideChar; overload; stdcall;
begin
  Result := WideChar(IntPtr(CharUpperW(LPWSTR(IntPtr(tch)))));
end;
编译器使用这个重载函数而不是旧函数,结果在我的问题中描述

为了避免此重载函数,我们必须更正typecast变量
Chr
,以获得正确的结果:

var
  Chr     :Char; //Or WideChar 
begin
  Chr := 'a';   
  Chr := Char(CharUpper(LPWSTR(ord(Chr))));
编辑:我们也可以调用Charupper API函数,如:

var
  Chr     :WideChar; //or Char
begin
  Chr := 'a';   
  Chr := Char(CharUpper(LPWSTR(ord(Chr))));
反汇编代码相同:

umCommon.pas.109: Chr := 'a';
0063A906 66BB6100         mov bx,$0061
umCommon.pas.110: Chr := Char(CharUpperW(LPWSTR(ord(Chr))));
0063A90A 0FB7C3           movzx eax,bx
0063A90D 50               push eax
0063A90E E8A9B1DDFF       call CharUpperW
0063A913 8BD8             mov ebx,eax


你能比较10.3和10.4(单位Winapi.Windows.pas)中
CharUpperW的声明吗?@zed 10.3和10.4中CharUpperW的声明是相同的!LPWSTR=PWideChar;函数CharUpperW(lpsz:LPWSTR):LPWSTR;stdcall;10.4从单个字符生成隐藏字符串,并将指向该字符串的指针放在CharUpperW上,然后将其全部关闭。Delphi 10.3中没有重载版本的
CharUpperW
,但两个变体都编译成功。另外,看看这个反汇编代码:-编译器将char值放在堆栈上,而不是指针上。当我们使用
WideChar('a')
调用函数时,它将指针置于适当的位置,这将导致AV。这一切意味着什么?很抱歉,但是您的WideChar第二个示例代码在版本10.4中得到的输出仍然与早期版本的Delphi不同。检查我的答案是否正确…我理解。10.3工作正常-它为
PWideChar('a')
输入单个字符值,或为宽字符串输入输入指针。这正是我们所需要的@GJ你能看看10.4下的反汇编代码吗?我认为编译器使用单字符输入时出错了。@GJ您不应该编辑答案,而是将其添加到您的问题中。对不起,我知道。。。我要快速按Remy Lebeau编辑,而不是我的。。。CorectedYeah<代码>大写
/
AnsiUpperCase
出于我的目的会变慢。
@s[1]
与执行PChar(s)相同@RemyLebeau它不是。在第一种情况下,编译器调用
UniqueStringU
,一切正常;在第二种情况下,它调用
UStrToPWChar
,并发生AV。@GJ。“
UpperCase
/
AnsiUpperCase
对我来说太慢了”-你试过了吗?@Remy Lebeau。不,我使用的是upcase table:UpCaseTable:Char的数组[Char];wich在程序开始时填充。函数
CharUpper
和重载无关,但typecast
ord(Chr)
do。再次打开反汇编代码,看看会发生什么。@zed right和typecasted也必须是
CharUpper
函数,正确答案。反汇编后的代码现在是相同的<代码>编译器使用这个重载函数,而不是旧的-不,它错了!在您的示例代码中,您直接调用
CharUpperW
,所以编译器并没有使用任何重载。由于编译器的新行为而发生错误。使用
ord
添加类型转换时,您强制新编译器的行为与以前的一样。@zed没有任何函数
charuperw
charuper
是相同的!检查unit
Winapi.Windows
中的函数
CharUpperW
也被重载!我没有10.4。如果
CharUpperW
以相同的方式重载,则可以像
Chr:=CharUpperW(Chr)一样使用它不是吗?
umCommon.pas.109: Chr := 'a';
0063A906 66BB6100         mov bx,$0061
umCommon.pas.110: Chr := Char(CharUpperW(LPWSTR(ord(Chr))));
0063A90A 0FB7C3           movzx eax,bx
0063A90D 50               push eax
0063A90E E8A9B1DDFF       call CharUpperW
0063A913 8BD8             mov ebx,eax