打印每个宽字符字节的字符值
printing the char value of each wide character's bytes
当 运行 以下情况时:
char acute_accent[7] = "éclair";
int i;
for (i=0; i<7; ++i)
{
printf("acute_accent[%d]: %c\n", i, acute_accent[i]);
}
我得到:
acute_accent[0]:
acute_accent[1]: �
acute_accent[2]: c
acute_accent[3]: l
acute_accent[4]: a
acute_accent[5]: i
acute_accent[6]: r
这让我觉得多字节字符 é
是 2 字节宽的。
然而,当 运行 这个(忽略编译器从 multi-character character constant
警告我之后):
printf("size: %lu",sizeof('é'));
我得到 size: 4
。
大小不同的原因是什么?
编辑:这个问题与 this 不同,因为它更多地是关于多字节字符编码、不同的 UTF 及其大小,而不是仅仅理解字符的大小。
来自 C99 standard,第 6.4.4.4 节:
2 An integer character constant is a sequence of one or more multibyte
characters enclosed in single-quotes, as in 'x'.
...
10 An integer character constant has type int.
sizeof(int)
在您的计算机上可能是 4,这就是您得到该结果的原因。
所以'é'
、'c'
、'l'
都是整型字符常量,所以都是int
类型,大小都是4。事实上有些是多字节的而有的不在这方面并不重要。
您看到差异的原因是因为在您的第一个示例中,字符 é
被编译器编码为两字节 UTF-8 代码点 0xC3 0xA9
.
看这里:
http://www.fileformat.info/info/unicode/char/e9/index.htm
并且正如 dbush 所描述的那样,字符 'é'
被编码为 UTF-32 代码点并以整数形式存储;因此它被表示为四个字节。
您的部分困惑源于通过以未定义的方式存储 Unicode 来使用实现定义的功能。
为防止未定义的行为,您应该始终清楚地识别字符串文字的编码类型。
例如:
char acute_accent[7] = u8"éclair"
这是非常糟糕的形式因为除非你自己算出来,否则你无法知道字符串的确切长度。事实上,我的编译器 (g++) 对我大吼大叫,因为虽然字符串是 7 个字节,但它总共有 8 个字节,最后是空字符。所以你实际上已经超出了缓冲区。
改用这个更安全:
const char* acute_accent = u8"éclair"
注意你的字符串实际上是 8 个字节:
#include <stdio.h>
#include <string.h> // strlen
int main() {
const char* a = u8"éclair";
printf("String length : %lu\n", strlen(a));
// Add +1 for the null byte
printf("String size : %lu\n", strlen(a) + 1);
return 0;
}
输出为:
String length : 7
String size : 8
另请注意 C 和 C++ 之间的字符大小不同!!
#include <stdio.h>
int main() {
printf("%lu\n", sizeof('a'));
printf("%lu\n", sizeof('é'));
return 0;
}
在 C 中输出是:
4
4
而在 C++ 中,输出是:
1
4
当 运行 以下情况时:
char acute_accent[7] = "éclair";
int i;
for (i=0; i<7; ++i)
{
printf("acute_accent[%d]: %c\n", i, acute_accent[i]);
}
我得到:
acute_accent[0]:
acute_accent[1]: �
acute_accent[2]: c
acute_accent[3]: l
acute_accent[4]: a
acute_accent[5]: i
acute_accent[6]: r
这让我觉得多字节字符 é
是 2 字节宽的。
然而,当 运行 这个(忽略编译器从 multi-character character constant
警告我之后):
printf("size: %lu",sizeof('é'));
我得到 size: 4
。
大小不同的原因是什么?
编辑:这个问题与 this 不同,因为它更多地是关于多字节字符编码、不同的 UTF 及其大小,而不是仅仅理解字符的大小。
来自 C99 standard,第 6.4.4.4 节:
2 An integer character constant is a sequence of one or more multibyte characters enclosed in single-quotes, as in 'x'.
...
10 An integer character constant has type int.
sizeof(int)
在您的计算机上可能是 4,这就是您得到该结果的原因。
所以'é'
、'c'
、'l'
都是整型字符常量,所以都是int
类型,大小都是4。事实上有些是多字节的而有的不在这方面并不重要。
您看到差异的原因是因为在您的第一个示例中,字符 é
被编译器编码为两字节 UTF-8 代码点 0xC3 0xA9
.
看这里:
http://www.fileformat.info/info/unicode/char/e9/index.htm
并且正如 dbush 所描述的那样,字符 'é'
被编码为 UTF-32 代码点并以整数形式存储;因此它被表示为四个字节。
您的部分困惑源于通过以未定义的方式存储 Unicode 来使用实现定义的功能。
为防止未定义的行为,您应该始终清楚地识别字符串文字的编码类型。
例如:
char acute_accent[7] = u8"éclair"
这是非常糟糕的形式因为除非你自己算出来,否则你无法知道字符串的确切长度。事实上,我的编译器 (g++) 对我大吼大叫,因为虽然字符串是 7 个字节,但它总共有 8 个字节,最后是空字符。所以你实际上已经超出了缓冲区。
改用这个更安全:
const char* acute_accent = u8"éclair"
注意你的字符串实际上是 8 个字节:
#include <stdio.h>
#include <string.h> // strlen
int main() {
const char* a = u8"éclair";
printf("String length : %lu\n", strlen(a));
// Add +1 for the null byte
printf("String size : %lu\n", strlen(a) + 1);
return 0;
}
输出为:
String length : 7
String size : 8
另请注意 C 和 C++ 之间的字符大小不同!!
#include <stdio.h>
int main() {
printf("%lu\n", sizeof('a'));
printf("%lu\n", sizeof('é'));
return 0;
}
在 C 中输出是:
4
4
而在 C++ 中,输出是:
1
4