【问题标题】:characters in c and c++c和c++中的字符
【发布时间】:2021-08-13 05:57:52
【问题描述】:

我问的是(我的理解完全正确吗?)

字符 x='b'; (x 有一个值可以用两种方式表示,一种是 int,另一种是 char 在两种语言 (C 和 C++))

在 C 中

如果我让编译器选择它将选择(将优先考虑) int 值,因为 C 的标准使字符文字为 int(优先考虑 int 而不是 char),就像这样代码

int main(){
    printf("%d", sizeof('b'));
    return 0;}

输出为:4 (int size),表示编译器首先将 b 视为 98,然后将其大小设为 int

但如果我在此代码中选择,我可以使用 char

int main(){
    char x = 'b';
    printf("%c", x);
    return 0;}

输出为:b (char)

在 C++ 中

如果我让编译器选择它将选择(将优先考虑) char 值,因为 C++ 的标准使字符文字为 char(优先考虑 char 而不是 int),就像这样代码

int main(){
    printf("%d", sizeof('b'));
    return 0;}

输出为:1(字符大小),表示编译器将 b 视为字符

但如果我在此代码中选择,我可以使用 int

int main(){
        char x = 'b';
        printf("%d", x);
        return 0;}

输出为 98(98 是 ASCII 码中表示 b 的 int)

【问题讨论】:

  • 除了 printf("%d", sizeof('b'); 不是有效的 C C++ 代码(printf 调用没有结束括号)之外,您还发送带有int 格式说明符的printfsize_t 参数,这是错误的。 %zu 是正确的说明符。
  • 问题是什么?
  • 类型的大小与其属性之间没有任何关系。 char 只是另一个整数类型,例如 int
  • 你的理解是正确的。在 C 中(以及在 C++ 中相关的地方),所有字符值都被读取为 unsigned char 转换为 int。请参阅“返回值”下的man 3 fgetcunsigned char 是您的 ASCII 码。通过将大小写为int,函数返回值可以与int 值(例如EOF)进行有效比较。因此'b'unsigned char 值是98,您可以在ASCII 表中看到。像fgetc() 这样的函数转换为int 以方便返回检查。在printf("%d", x);中,x被隐式转换为int,最好使用%hhu
  • 字符文字是 C 中的 int 和 C++ 中的 char。

标签: c++ c


【解决方案1】:
  • 字符常量,这个:'A',在 C 中属于 int 类型,在 C++ 中属于 char 类型。编译器选择相应语言标准指定的类型。

  • char 类型的已声明字符变量始终为 char 和 1 字节大(在非外部系统上通常为 8 位)。

  • printf("%c", some_char); 是一个可变参数函数(接受任意数量的参数)并且具有特殊的隐式类型提升规则。称为默认参数提升的东西会将传递的字符变量整数提升为int。在此处阅读有关整数提升的信息:Implicit type promotion rules

    printf 期望提升发生,因此%c 将意味着根据printf 的内部结构将参数转换回char。这在 C++ 中也适用,但应避免使用 stdio.h。

  • printf("%d", x); 如果xchar,这将是未定义的行为。但在实践中,可能会发生上述整数提升,因此它会打印一个整数。另请注意,char 没有什么神奇之处,它们只是 1 字节的大整数。所以它在转换之前已经有值 98。

【讨论】:

  • 我改变了一些东西你能看看并回答我(我的理解现在完全正确吗?)@Lundin
【解决方案2】:

你说的有些是真的,有些是错误的。让我们依次浏览它们。

char x='b';x 有两个值,一个是int,另一个是char,两种语言(C 和 C++))

嗯,不,不是真的。当您说char x 时,您会得到一个通常能够容纳一个字符的变量,这在 C 和 C++ 中都是完美的,同样如此。正如我们将看到的,唯一的区别是字符常量'b'类型不是值)。

如果我让编译器选择,在 C 中

我不确定你所说的“选择”是什么意思,因为这件事实际上没有任何选择。

它将选择(将优先考虑)int 值,如此代码中的值
printf("%d", sizeof('b'));
输出为: 4 (int size) 这意味着编译器首先将 b 更改为 98 并将其大小设为 int

不完全是。你得到 4 是因为,是的,像 'b' 这样的字符常量的 typeint。在 ASCII 中,字符常量 'b' 无论如何都具有值 98。编译器这里没有把字符改成int,这里的值也没有从'b'变成98。它一直是一个 int(因为这是 C 中字符常量的类型),并且它一直都有值 98(因为这是 ASCII 中字母 b 的值)。

但如果我在此代码中选择,我可以使用 char 值 `printf("%c", x);

没错。但这并没有什么神奇之处。考虑:

char c1 = 'b';
int i1 = 'b';
char c2 = 98;
int i2 = 98;
printf("%c %c %c %c\n", c1, i1, c2, i2);
printf("%d %d %d %d\n", c1, i1, c2, i2);

打印出来

b b b b
98 98 98 98

您可以使用%c 打印intchar,您将获得具有该值的字符。
您可以使用%d 打印intchar,您将获得一个数值。
(稍后会详细介绍。)

在 C++ 中,如果我让编译器选择它将选择(将优先考虑)此代码中的 char 值
printf("%d", sizeof('b'));
输出为:1(字符大小),这意味着编译器没有将 b 更改为 int

您看到的是 C 和 C++ 之间的一大区别:像 'b' 这样的字符常量在 C 中是 int 类型,但在 C++ 中是 char 类型。 (为什么会这样?我稍后会推测。)

但如果我在此代码中选择这样的值,我可以使用 int 值
char x = 'b';
printf("%d", x);
输出为 98(98 是 int,它代表 ASCII 码中的 b

没错。这在 C 和 C++ 中的工作方式完全相同。 (我之前的 c1i1c2i2 的 printfs 在 C 和 C++ 中的工作方式完全相同。)

那么为什么字符常量的类型不同呢?我不确定,但我相信是这样的:

C 喜欢将所有内容推广到int。 (顺便说一句,这就是我们能够将字符直接传递给printf 并使用%d 打印它们的原因:在传递给printf 之前,这些字符都被提升为int,所以它工作得很好。)所以有拥有char 类型的字符常量是没有意义的,因为任何时候你使用一个,对于任何事情,它都会被提升为int。所以字符常量也可以从 int 开始。

另一方面,在 C++ 中,事物的类型更为重要。您可能有两个重载函数f(int)f(char),如果您调用f('b'),显然您希望调用的f() 版本接受char。所以在 C++ 中有一个理由,一个很好的理由,让字符常量为 char 类型,就像它们看起来一样。


附录:

你在这里问的基本问题,我们在这个答案和这些 cmets 中一直在跳舞,是在 C 中(就像在大多数语言中一样)有几种形式的常量,让你以方便且对您有意义的形式编写常量。对于您可以编写的任何不同形式的常量,有几个有趣的事情,但最重要的是实际值是什么?类型是什么?

举例说明这一点可能更容易。以下是在 C 或 C++ 程序中表示常量值 98 的相当多的方法:

Form of constant base type value
98 10 int 98
0142 8 unsigned 98
0x62 16 unsigned 98
98. 10 double 98
9.8e1 10 double 98
98.f 10 float 98
9.8e1f 10 float 98
98L 10 long 98
98U 10 unsigned 98
'b' ASCII int/char 98

这张表甚至不完整;用 C 和 C++ 编写常量的方法远不止这些。

但除了一个例外,此表中的每一行都同样适用于 C 和 C++,除了最后一行。在 C 中,字符常量的类型是int。在 C++ 中,字符常量的类型是char

常量的类型决定了常量出现在更大的表达式中时会发生什么。在这方面,常量的类型类似于变量的类型。如果我写

int a = 1, b = 3;
double c = a / b;

它不能正常工作,因为 C 中的规则是,当你将一个 int 除以一个 int 时,你会得到截断整数除法。但关键是操作数的类型直接决定了表达式的含义。因此,从这两行的不同行为可以看出,常量的类型也变得非常有趣:

double c2 = 1 / 3;
double c3 = 1. / 3;

同样,常量的类型是int 还是类型char 也会有所不同。取决于字符常量是 int 还是 char 类型的表达式在 C 和 C++ 中的行为会略有不同。 (实际上,几乎唯一可以轻易看出的区别在于sizeof。)

为了完整起见,在同一框架中查看其他几种形式的字符常量可能会很有用:

Form of constant base type value
'b' ASCII int/char 98
'\142' 8 int/char 98
'\x62' 16 int/char 98

【讨论】:

  • 我改变了一些东西你能看看并回答我(我的理解现在完全正确吗?)@Steve Summit
  • @FadyHany 你的编辑对我来说没有太大变化。您仍然在说“如果我让编译器选择它将选择(将优先考虑) int 值”之类的话。这本身并没有,但它也没有真正的意义。它与编译器使用的模型并不真正匹配;它并没有真正告诉您有关在您正在编写的程序中使用字符常量的任何有用信息。我在我的答案中添加了一个部分,给出了我认为一个有用的模型,并解释了常量在 C 和 C++ 中的工作方式。
  • 如果我们忽略“如果我让编译器选择”部分,我的理解将完全正确(没有错)? @史蒂夫峰会
  • @FadyHany 我认为您仍然缺少的一点是 C 和 C++ 中的字符和整数之间没有那么大的区别。我认为考虑将b 之类的字符转换 为整数是没有用的。在 C 和 C++ 中,像 b 这样的字符是 一个整数。在计算机内部,它由二进制数 01100010 表示,这与数字 98 的表示方式完全相同。如果您将二进制数 01100010 存储在寄存器中,您实际上无法判断它是数字 98 还是字符 b
  • 我知道 char 是内存中的一个 int 它只能用 %c 表示为 char 并且八进制和十六进制也是内存中的整数是你的意思吗?@Steve Summit
猜你喜欢
  • 2021-01-27
  • 2015-10-28
  • 1970-01-01
  • 1970-01-01
  • 2020-06-14
  • 2011-04-10
相关资源
最近更新 更多