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

GJ.*_*GJ. 5 delphi

CharUpper有人知道 Delphi 10.3 中的声明与CharUpperWDelphi 10.4 中不同的原因吗?

Delphi 10.3 中的正确声明

    var
      chr   :WideChar;
    begin      
      chr := WideChar(CharUpperW(PWideChar('a'))); //chr = 'A'
//    chr := WideChar(CharUpperW(WideChar('a')));  //raise exeption: "access violation...
Run Code Online (Sandbox Code Playgroud)

Delphi 10.4 中的正确声明

    var
      chr   :WideChar;
    begin   
//    chr := WideChar(CharUpperW(PWideChar('a')));  //raise exeption: "access violation...
      chr := WideChar(CharUpperW(WideChar('a')));   //chr = 'A'
Run Code Online (Sandbox Code Playgroud)

编辑:Remy Lebeau 对 PWideChar 的解释是正确的,但 Delphi 10.4 版和更早版本仍然存在差异!

Lebeau解释代码示例在10.4版本及更早版本中编译,但函数的输出不同。10.4 之前的所有版本都得到正确的输出“A”!

var
  char , chr : WideChar;
begin
  chr := 'a';
  char := WideChar(CharUpperW(PWideChar(chr)));
end;
Run Code Online (Sandbox Code Playgroud)

10.4 下的此示例无法正常工作,输出是随机字符。

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

LPWSTR = PWideChar; 
function CharUpperW(lpsz: LPWSTR): LPWSTR; stdcall;**
Run Code Online (Sandbox Code Playgroud)

编辑:在 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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

GJ.*_*GJ. -1

好的,在您的帮助下,我找到了答案...实际上,函数CharUpperCharUpperW都在Winapi.Windows单元中,并且都调用相同的 API 调用CharUpperW。但在 Delphi 10.4 版本中,unitWinapi.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;
Run Code Online (Sandbox Code Playgroud)

编译器采用此重载函数而不是旧函数,结果在我的问题中进行了描述。

为了避免这种重载函数,我们必须更正类型转换变量Chr以获得正确的结果:

var
  Chr     :Char; //Or WideChar 
begin
  Chr := 'a';   
  Chr := Char(CharUpper(LPWSTR(ord(Chr))));
Run Code Online (Sandbox Code Playgroud)

编辑:我们还可以调用 CharUpperW API 函数,例如:

var
  Chr     :WideChar; //or Char
begin
  Chr := 'a';   
  Chr := Char(CharUpper(LPWSTR(ord(Chr))));
Run Code Online (Sandbox Code Playgroud)

反汇编后的代码是一样的:

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
Run Code Online (Sandbox Code Playgroud)