wchar_t是无符号的还是有符号的?

13
在本链接中,unsigned wchar_ttypedefWCHAR。但我在我的 SDK winnt.h 或 mingw winnt.h 中找不到这种类型定义。 wchar_t 是有符号的还是无符号的?
我正在使用 C 语言中的 WINAPIs。

一个类似的问题:https://dev59.com/1HE95IYBdhLWcg3wPbd7 - Andriy
我认为那个页面是错误的。该库“曾经”在编译器没有内置wchar_t类型时使用unsigned short。猜测在更改为wchar_t时,unsigned只是被错误地留在了那里。 - Bo Persson
2
无论有符号还是无符号,你都不应该使用它。请参阅 utf8everywhere.org。 - Pavel Radzivilovsky
2
@Pavel:一般来说,当你需要编写粘合代码、编译器测试、调试器的字符串解码器或其他许多有效用例时,你别无选择,只能使用wchar_t。笼统的绝对规定往往没有什么帮助。 - Cameron
5个回答

17

wchar_t的有无符号是未指定的。标准只说明(3.9.1/5):

类型wchar_t应该和其他整数类型中的一个被称为底层类型的类型具有相同的大小、符号和对齐要求(3.11)。

(相比之下,类型char16_tchar32_t明确为无符号。)


6
尽管如此,Windows API 的定义似乎是无符号的。 - netcoder
2
@netcoder:“未指定”并不意味着没有人被允许定义它。它只是表示标准没有规定有符号性。 - Kerrek SB
9
我知道标准上是怎么说的,也知道它是怎么运作的。但这个问题被打上了 winapi 的标签,所以我认为这额外的信息仍然是有用的。 - netcoder
2
@netcoder,是的,它很有用。谢谢。请查看我帖子中的链接。 - 2vision2
2
@user1317084:你的问题是关于C语言,还是关于WinAPI如何实现C语言中某些实现定义方面的内容?如果你能澄清一下就好了。 - Kerrek SB
显示剩余3条评论

1

请注意,类型在不同平台上的长度会有所变化。

Windows 使用 UTF-16 编码,wchar_t 占用 2 个字节。Linux 则使用 4 个字节的 wchar_t。


1
在我看过的大多数Linux系统上,wchar_t是一个32位类型,可能用于UTF-32数据。 - jamesdlin
已解决。我已经好几年没用Unicode了 - 我记得Linux使用UTF-8,但如果是这样,为什么要有一个四字节的wchar_t? - user82238
2
大多数现代Linux系统通常使用UTF-8。这就是char的作用。32位的wchar_t对于需要固定宽度编码的UTF-32非常有用。 - jamesdlin

1
标准可能不会规定wchar_t是有符号的还是无符号的,但是Microsoft会这样做。即使你的非Microsoft编译器不同意,Windows API也将使用来自/Zc:wchar_t (wchar_t Is Native Type)的定义:

Microsoft将wchar_t实现为两个字节的无符号值。它映射到Microsoft特定的本机类型__wchar_t


0

-2

我在多个平台上进行了测试,没有进行任何优化。

1) MinGW (32-bit) + gcc 3.4.4:
---- snip ----
#include<stdio.h>
#include<wchar.h>
const wchar_t BOM = 0xFEFF;
int main(void)
{
    int c = BOM;
    printf("0x%08X\n", c+0x1000);
    return 0;
}
---- snip ----

它打印出0x00010EFFwchar_t是无符号的。 相应的汇编代码说movzwl _BOM, %eax。不是movSwl,而是movZwl
2) FreeBSD 11.2 (64-bit) + clang 6.0.0:
---- snip ----
#include<stdio.h>
#include<wchar.h>
const wchar_t INVERTED_BOM = 0xFFFE0000;
int main(void)
{
     long long c = INVERTED_BOM;
     printf("0x%016llX\n", c+0x10000000LL);
     return 0;
}
---- snip ----

它打印了0x000000000EFF0000wchar_t是带符号的。 相应的汇编代码说:movq $-131072, -16(%rbp)。32位的0xFFFE0000被提升为64位带符号的-131072

3)与2)相同的代码,在RedHat(版本未知)+gcc 4.4.7上:它再次打印0x000000000EFF0000wchar_t是带符号的。

我没有测试printf的实现,也没有测试WinAPI的WCHAR定义,但测试了编译器内置的wchar_t类型(在任何头文件中都没有关于其带符号性的规定)以及C-to-ASM编译器引擎的行为。

请注意,1)和3)上的编译器由同一供应商GNU Project提供。答案肯定取决于平台。(有人可以在Visual C ++上测试吗?)


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