非Unicode应用程序是什么?

5
我们知道,在Windows系统中,我们可以在“控制面板\时钟、语言和区域”中为非Unicode程序设置本地化语言。但是对于应用程序来说,本地化语言意味着什么呢?据我了解,应用程序是一个编译后的二进制可执行文件,它只包含机器代码指令而没有数据,那么字符编码如何影响它们的运行呢?
一种猜测是,如果可执行文件在代码段中包含一些文字字符串,它将使用某个内部字符集对它们进行编码。如果字符集不是Unicode,则会显示垃圾字符。但是内部字符集不是固定的吗?就像Java中,Java规范定义了内部编码为UTF-16。
希望有人能回答我的问题,
谢谢。

1
请注意,Unicode并不意味着UTF16,但在Windows上它确实是。他们应该在15年前就改为UTF8,这个问题就不会存在了。 - Matt Joiner
@Matt Joiner:实际上,这个问题仍然存在。请记住,我们在谈论_非Unicode_程序。它们完全不关心_Unicode_程序使用UTF8还是UTF16。 - MSalters
3个回答

5
Windows有两种程序可以与其通信的方法,称为“ANSI API”和“Unicode API”,而“非Unicode应用程序”是指通过“ANSI API”而不是“Unicode API”与Windows通信的应用程序。
这意味着应用程序传递给Windows的任何字符串都只是一系列字节,而不是一系列Unicode字符。 Windows必须决定该字节序列对应哪些字符,你所说的控制面板设置就是它如何实现的。
例如,一个输出值为0xE4的字节的非Unicode程序在设置为使用Windows Western的PC上将显示字符ä,而在设置为希伯来语的PC上将显示字符ה。

在“ANSI API”中,“一个字节”意味着屏幕上的“一个字符”。而在Unicode中,屏幕上的一个字符可以由多个字节表示。 - Prof. Falken
1
@Amigable Clark Kant:并不总是正确的 - "双字节字符集"(请参见http://msdn.microsoft.com/en-us/library/dd317794%28VS.85%29.aspx)仍然使用ANSI API。否则,在Unicode之前就不可能有中文版Windows! - RichieHindle
值得注意的是,微软很容易将UTF-8作为支持的多字节字符集添加进去,从而解决整个问题,但他们拒绝这样做 - R.. GitHub STOP HELPING ICE
@RichieHindle:解释得很好。正如你所说,当应用程序调用Windows API时,它只是传递“一系列字节”。那么编码中的“字节序列”是否与源代码相同呢?我的意思是,如果源代码是用UTF-8编写的,那么它们就是UTF-8;如果源代码是GBK,则字节序列就是GBK。这意味着ANSI C没有固定的内部编码,就像Java所做的那样(utf-16)。 - Alfred
@RichieHindle:实际上,编译器必须从源字符集转换为执行字符集,因此从非Unicode程序输出的字符串文字在技术上不需要由源代码中存在的相同字节组成。 - ninjalj
显示剩余4条评论

1

RichieHindle正确地解释了大多数API的两个变体,即*W(Unicode)和*A(ANSI)变体。但在此之后,他略有错误。

重要的是要知道,*A变体(例如MessageBoxA)只是*W版本(例如MessageBoxW)的包装器。它们将输入字符串转换为Unicode;它们将输出字符串转换回来。

在Windows SDK中,对于所有这样的A/W对,都有一个#ifdef UNICODE块,使得MessageBox()是一个扩展到MessageBoxA()MessageBoxW()的宏。因为所有宏都使用相同的条件,所以许多程序使用100%的*A函数或100%的*W函数。 "非Unicode"应用程序是那些没有定义UNICODE,因此仅使用*A变体的应用程序。

然而,您完全可以混合使用 *A 和 *W 函数。混用 *A 和 *W 函数的程序是否被认为是“Unicode”、“非Unicode”甚至其他东西?实际上,答案也是混合的。当涉及到时钟、语言和区域设置时,应用程序在进行 *W 调用时被视为Unicode应用程序,而进行 *A 调用时则被视为非Unicode应用程序 - 设置控制 *A 包装器如何转换为 *W 调用。在多线程程序中,因此您可以同时拥有两者(!)
所以,回到 RichieHindle 的例子,如果您使用值 (char)0xE4 调用 *A 函数,则包装器将根据此设置将其转发到 *W 函数,其中 L'ä'L'ה' 取决于设置。如果您直接使用值 (WCHAR)0x00E4 调用 *W 函数,则不会进行转换。

0
一个非 Unicode 应用程序主要使用多字节编码,其中字符串由 char* 表示,而不是 wchar_t*:
char* myString;

通过更改使用的编码,您可以更改应用程序可用的字符集。

大多数应用程序都包含指令和数据。


1
@Amigable Clark Kant:不,"multi-byte" 对于 ANSI API 和使用 char 是正确的。例如,请参见 MultiByteToWideChar API,其中 MultiByte 表示非 Unicode,而 WideChar 表示 Unicode。 - RichieHindle
1
答案和评论应该解释这是由微软创建的不正确术语。Unicode 的主要编码是 UTF-8,它是一种多字节编码,存在一些系统其宽字符编码不是 Unicode。实际上,人们可以认为在 Windows 上它并不是 Unicode,因为 Windows 的 wchar_t 太小,无法存储任意的 Unicode 代码点... - R.. GitHub STOP HELPING ICE
@Alexander Rafferty:那么对于数据段,ANSI C中使用的内部编码是什么?它是否由C定义或者我们可以更改它? - Alfred
@RichieHindle:MultiByte 意味着多字节,而 WideChar 意味着宽字符。有很多系统使用 utf-8 来处理多字节字符,而 C 标准中并没有规定宽字符应该是 Unicode 还是 ISO/IEC 10646。 - ninjalj
1
@Guoqin:我希望你不要混淆 ANSI C(大致相当于 ISO 9899、ISO C)和 Windows ANSI API,后者因为 Windows 使用的某些代码页是基于 ANSI 标准草案而得名。 - ninjalj
@ninjalj:可以说C标准通过指定预定义的__STDC_ISO_10646__宏,暗示了wchar_t应该是Unicode。 - R.. GitHub STOP HELPING ICE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接