Char变量输入一个大于127的值,返回的结果问题

拜你所赐 2021-04-30 09:43:53
例如这个代码:
#include<stdio.h>
void main()
{
char c1,c2;
c1 = 197;
c2 = 198;
printf("c1 = %c,c2 = %c\n",c1,c2 );
printf("c1 = %d,c2 = %d",c1,c2);
return;
}


返回的是[
c1 = ?c2 = ?
c1 = -59,c2 = -58


想问一下返回的%d值是怎么计算的,观察的结果是   
比如c1转2进制:11000101 然后首位1保留 其他的取补码 1 0111010
这样的结果计算出来是终端返回的结果,
想知道这样对吗?为什么会这么计算?
...全文
3042 11 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复 1
计算机底层是以二进制补码形式存储的,取数时会还原成原码,char占1字节,也就是8位,最高位为符号位,把197转成二进制就是11000101,而正数的原码反码补码都是一样的,但因为这里最高位为1,机器会把他当做负数,把它转换为原码之后就是-59了
拜你所赐 2021-05-06
  • 打赏
  • 举报
回复
引用 10 楼 均陵鼠侠的回复:
[quote=引用 6 楼 拜你所赐 的回复:][quote=引用 5 楼 均陵鼠侠 的回复:][quote=引用 4 楼 拜你所赐 的回复:][quote=引用 3 楼 均陵鼠侠 的回复:]这是一个简单而又复杂的问题。 首先, %c 和 %d 都要求对应的变参是 int 类型。唯一不同的是,%c 是将这个 int 类型的变参转换为 unsigned char 类型的字符,然后予以显示,而 %d 则是将它转换为有符号十进制格式的数字字符予以显示。 其次,程序是没有问题的。尽管传入的变参是 char 类型的,但依照默认实参转换(default argument conversion)的规则,它是被转换为 int 类型之后传递给 printf 的。 最后,对于 printf 来说, %c 是将传入的值按 int 类型(的长度)取出,然后转换(缩小)为 unsigned char 类型(的长度),将它视为字符编码,然后打印这个字符; %d 是将传入的值按 int 类型(的长度)取出,拆分数位并转换为有符号十进制数字字符打印输出。这里的关键是, %d 要求这个转换过程必须区分数值的正负。这很好办,只需要判断其二进制形式的最高位(符号位)就可以了:为0是正数,为1是负数。然而,在197和198这两个数值的二进制形式中,符号位似乎并不是1。这就回到了开始:在将 char 类型的值转换为 int 类型并传递给 printf 时,是如何转换的?再往前,两个常量197和198的类型都是 int ,将它们赋给变量 c1 和 c2 时,需要从 int 转换为 char ,这个转换过程又是怎样的? 这就涉及到数值转换规则。首先,将一个整数类型的值转换为另一个除_Bool之外的整数类型时,如果这个值能够用新类型来表示,则转换后的值不变。 来看
char c1, c2;
c1 = 197;
c2 = 198;
在这里,如果 char 等价于 unsigned char ,那么,在主流的机器上,它可以表示的数值范围是 0到255,所以能够容纳,且 printf 不可能打印两个负值。显然,在楼主的环境下,char实际上是signed char。在主流的机器上,它可以表示的数值范围是-127到+128,故无法表示 197 和 198 ,需要转换。 但是,如果新类型是有符号的并且无法表示这个值,转换的结果要依赖于具体的编译器,甚至可能触发信号机制。即,C语言没有规定如何转换。 在很多平台上(显然包括楼主所在的机器环境),是直接把长度为 int 的 197 截断为 char 类型的长度。所以,最终它表示有符号数-59。
您好,非常感谢您的回复,我使用的编译器是VS2012。我是一个C语言的初学者,我对您的回复还有一些疑问,在您的回复中说到“在197和198这两个数值的二进制形式中,符号位似乎并不是1。”197 -->11000101 198 --> 11000110 直接转化成二进制的首位是否会直接成为符号位呢?烦请您帮忙把197到-59的过程详细说一下吗?[/quote] 对,我这两句话没说明白。 赋给 c1 和 c2 的值来自于常量 197 和 198 ,这两个常量的类型是 int 。所以,它们的最高位不是1,而是0。即,如果 int 类型的长度是 32 位,则 197 的二进制形式为 00000000000000000000000011000101 。把它截断为 char 类型的长度时,如果 char 类型的长度是 8,则截断后是 11000101 。[/quote]十分感谢您的解答,还有一个问题我没有搞明白,例如197.对于截断后的二进制11000101。它的最高位是1,即后面表示数值的二进制是“1000101”,转变成二进制之后为69。但是取其补码之后即为“0111010”它的十进制是“58”。截断之后为什么不是直接输出它的十进制而是取其补码呢?这点我有点搞不明白。[/quote] 对机器来说,截断之后,如果最高位是1,即表明它是一个负数,而负数本身就是采用补码的,不需要也不会再次转换为补码。要么是你把机器想得太复杂了,要么是一些不正确的说法影响了你的思维。 另一方面,负数有三种表示方法:符号带大小、对1的补码和对2的补码,C语言并没有限定采用哪种表示方法,这个取决于平台和编译器,只不过对2的补码是普遍的情况。无论采用哪种表示方法,从编程和运行的层面上基本上看不到,也不需要过问,毕竟它不影响输出和结果的正确性。所以,说负数采用补码,眼光过于局限了。[/quote] 谢谢老师,看了老师的回复才豁然开朗,钻了牛角尖,把机器想的太过于复杂了,十分感谢老师的解答!
均陵鼠侠 2021-05-01
  • 打赏
  • 举报
回复
引用 6 楼 拜你所赐 的回复:
[quote=引用 5 楼 均陵鼠侠 的回复:][quote=引用 4 楼 拜你所赐 的回复:][quote=引用 3 楼 均陵鼠侠 的回复:]这是一个简单而又复杂的问题。 首先, %c 和 %d 都要求对应的变参是 int 类型。唯一不同的是,%c 是将这个 int 类型的变参转换为 unsigned char 类型的字符,然后予以显示,而 %d 则是将它转换为有符号十进制格式的数字字符予以显示。 其次,程序是没有问题的。尽管传入的变参是 char 类型的,但依照默认实参转换(default argument conversion)的规则,它是被转换为 int 类型之后传递给 printf 的。 最后,对于 printf 来说, %c 是将传入的值按 int 类型(的长度)取出,然后转换(缩小)为 unsigned char 类型(的长度),将它视为字符编码,然后打印这个字符; %d 是将传入的值按 int 类型(的长度)取出,拆分数位并转换为有符号十进制数字字符打印输出。这里的关键是, %d 要求这个转换过程必须区分数值的正负。这很好办,只需要判断其二进制形式的最高位(符号位)就可以了:为0是正数,为1是负数。然而,在197和198这两个数值的二进制形式中,符号位似乎并不是1。这就回到了开始:在将 char 类型的值转换为 int 类型并传递给 printf 时,是如何转换的?再往前,两个常量197和198的类型都是 int ,将它们赋给变量 c1 和 c2 时,需要从 int 转换为 char ,这个转换过程又是怎样的? 这就涉及到数值转换规则。首先,将一个整数类型的值转换为另一个除_Bool之外的整数类型时,如果这个值能够用新类型来表示,则转换后的值不变。 来看
char c1, c2;
c1 = 197;
c2 = 198;
在这里,如果 char 等价于 unsigned char ,那么,在主流的机器上,它可以表示的数值范围是 0到255,所以能够容纳,且 printf 不可能打印两个负值。显然,在楼主的环境下,char实际上是signed char。在主流的机器上,它可以表示的数值范围是-127到+128,故无法表示 197 和 198 ,需要转换。 但是,如果新类型是有符号的并且无法表示这个值,转换的结果要依赖于具体的编译器,甚至可能触发信号机制。即,C语言没有规定如何转换。 在很多平台上(显然包括楼主所在的机器环境),是直接把长度为 int 的 197 截断为 char 类型的长度。所以,最终它表示有符号数-59。
您好,非常感谢您的回复,我使用的编译器是VS2012。我是一个C语言的初学者,我对您的回复还有一些疑问,在您的回复中说到“在197和198这两个数值的二进制形式中,符号位似乎并不是1。”197 -->11000101 198 --> 11000110 直接转化成二进制的首位是否会直接成为符号位呢?烦请您帮忙把197到-59的过程详细说一下吗?[/quote] 对,我这两句话没说明白。 赋给 c1 和 c2 的值来自于常量 197 和 198 ,这两个常量的类型是 int 。所以,它们的最高位不是1,而是0。即,如果 int 类型的长度是 32 位,则 197 的二进制形式为 00000000000000000000000011000101 。把它截断为 char 类型的长度时,如果 char 类型的长度是 8,则截断后是 11000101 。[/quote]十分感谢您的解答,还有一个问题我没有搞明白,例如197.对于截断后的二进制11000101。它的最高位是1,即后面表示数值的二进制是“1000101”,转变成二进制之后为69。但是取其补码之后即为“0111010”它的十进制是“58”。截断之后为什么不是直接输出它的十进制而是取其补码呢?这点我有点搞不明白。[/quote] 对机器来说,截断之后,如果最高位是1,即表明它是一个负数,而负数本身就是采用补码的,不需要也不会再次转换为补码。要么是你把机器想得太复杂了,要么是一些不正确的说法影响了你的思维。 另一方面,负数有三种表示方法:符号带大小、对1的补码和对2的补码,C语言并没有限定采用哪种表示方法,这个取决于平台和编译器,只不过对2的补码是普遍的情况。无论采用哪种表示方法,从编程和运行的层面上基本上看不到,也不需要过问,毕竟它不影响输出和结果的正确性。所以,说负数采用补码,眼光过于局限了。
aguang 2021-05-01
  • 打赏
  • 举报
回复
数值197是int类型, 赋值于char类型c1, 高位将被截去,即为11000101

当输出格式为%c: 按C定义:字符输出不会是负值, 所以结果为"?";
当输出格式为%d: char类型变量如果没有加限定符(signed/unsigned),由机器本身规则确定是按符号数或无符号数处理.

就楼主例子, 由于对c1/c2没有用限定符,楼主机器是按符号数输出的.
qybao 2021-05-01
  • 打赏
  • 举报
回复
计算机是按补码来存储的,所以截断后的11000101是补码,其中最高位的1是符号为表示是负数,后7位补码1000101转为原码是0111011,十进制是59,所以就是-59
拜你所赐 2021-04-30
  • 打赏
  • 举报
回复
引用 1 楼 NorZ 的回复:
百度“负数、补码” %c问号的原因是因为找不到对应的ASCII字符
我知道%c是找不到字符 就是不是很理解他那个%d输出的原理
拜你所赐 2021-04-30
  • 打赏
  • 举报
回复
引用 5 楼 均陵鼠侠 的回复:
[quote=引用 4 楼 拜你所赐 的回复:][quote=引用 3 楼 均陵鼠侠 的回复:]这是一个简单而又复杂的问题。 首先, %c 和 %d 都要求对应的变参是 int 类型。唯一不同的是,%c 是将这个 int 类型的变参转换为 unsigned char 类型的字符,然后予以显示,而 %d 则是将它转换为有符号十进制格式的数字字符予以显示。 其次,程序是没有问题的。尽管传入的变参是 char 类型的,但依照默认实参转换(default argument conversion)的规则,它是被转换为 int 类型之后传递给 printf 的。 最后,对于 printf 来说, %c 是将传入的值按 int 类型(的长度)取出,然后转换(缩小)为 unsigned char 类型(的长度),将它视为字符编码,然后打印这个字符; %d 是将传入的值按 int 类型(的长度)取出,拆分数位并转换为有符号十进制数字字符打印输出。这里的关键是, %d 要求这个转换过程必须区分数值的正负。这很好办,只需要判断其二进制形式的最高位(符号位)就可以了:为0是正数,为1是负数。然而,在197和198这两个数值的二进制形式中,符号位似乎并不是1。这就回到了开始:在将 char 类型的值转换为 int 类型并传递给 printf 时,是如何转换的?再往前,两个常量197和198的类型都是 int ,将它们赋给变量 c1 和 c2 时,需要从 int 转换为 char ,这个转换过程又是怎样的? 这就涉及到数值转换规则。首先,将一个整数类型的值转换为另一个除_Bool之外的整数类型时,如果这个值能够用新类型来表示,则转换后的值不变。 来看
char c1, c2;
c1 = 197;
c2 = 198;
在这里,如果 char 等价于 unsigned char ,那么,在主流的机器上,它可以表示的数值范围是 0到255,所以能够容纳,且 printf 不可能打印两个负值。显然,在楼主的环境下,char实际上是signed char。在主流的机器上,它可以表示的数值范围是-127到+128,故无法表示 197 和 198 ,需要转换。 但是,如果新类型是有符号的并且无法表示这个值,转换的结果要依赖于具体的编译器,甚至可能触发信号机制。即,C语言没有规定如何转换。 在很多平台上(显然包括楼主所在的机器环境),是直接把长度为 int 的 197 截断为 char 类型的长度。所以,最终它表示有符号数-59。
您好,非常感谢您的回复,我使用的编译器是VS2012。我是一个C语言的初学者,我对您的回复还有一些疑问,在您的回复中说到“在197和198这两个数值的二进制形式中,符号位似乎并不是1。”197 -->11000101 198 --> 11000110 直接转化成二进制的首位是否会直接成为符号位呢?烦请您帮忙把197到-59的过程详细说一下吗?[/quote] 对,我这两句话没说明白。 赋给 c1 和 c2 的值来自于常量 197 和 198 ,这两个常量的类型是 int 。所以,它们的最高位不是1,而是0。即,如果 int 类型的长度是 32 位,则 197 的二进制形式为 00000000000000000000000011000101 。把它截断为 char 类型的长度时,如果 char 类型的长度是 8,则截断后是 11000101 。[/quote]十分感谢您的解答,还有一个问题我没有搞明白,例如197.对于截断后的二进制11000101。它的最高位是1,即后面表示数值的二进制是“1000101”,转变成二进制之后为69。但是取其补码之后即为“0111010”它的十进制是“58”。截断之后为什么不是直接输出它的十进制而是取其补码呢?这点我有点搞不明白。
NorZ 2021-04-30
  • 打赏
  • 举报
回复
百度“负数、补码” %c问号的原因是因为找不到对应的ASCII字符
均陵鼠侠 2021-04-30
  • 打赏
  • 举报
回复
引用 4 楼 拜你所赐 的回复:
[quote=引用 3 楼 均陵鼠侠 的回复:]这是一个简单而又复杂的问题。 首先, %c 和 %d 都要求对应的变参是 int 类型。唯一不同的是,%c 是将这个 int 类型的变参转换为 unsigned char 类型的字符,然后予以显示,而 %d 则是将它转换为有符号十进制格式的数字字符予以显示。 其次,程序是没有问题的。尽管传入的变参是 char 类型的,但依照默认实参转换(default argument conversion)的规则,它是被转换为 int 类型之后传递给 printf 的。 最后,对于 printf 来说, %c 是将传入的值按 int 类型(的长度)取出,然后转换(缩小)为 unsigned char 类型(的长度),将它视为字符编码,然后打印这个字符; %d 是将传入的值按 int 类型(的长度)取出,拆分数位并转换为有符号十进制数字字符打印输出。这里的关键是, %d 要求这个转换过程必须区分数值的正负。这很好办,只需要判断其二进制形式的最高位(符号位)就可以了:为0是正数,为1是负数。然而,在197和198这两个数值的二进制形式中,符号位似乎并不是1。这就回到了开始:在将 char 类型的值转换为 int 类型并传递给 printf 时,是如何转换的?再往前,两个常量197和198的类型都是 int ,将它们赋给变量 c1 和 c2 时,需要从 int 转换为 char ,这个转换过程又是怎样的? 这就涉及到数值转换规则。首先,将一个整数类型的值转换为另一个除_Bool之外的整数类型时,如果这个值能够用新类型来表示,则转换后的值不变。 来看
char c1, c2;
c1 = 197;
c2 = 198;
在这里,如果 char 等价于 unsigned char ,那么,在主流的机器上,它可以表示的数值范围是 0到255,所以能够容纳,且 printf 不可能打印两个负值。显然,在楼主的环境下,char实际上是signed char。在主流的机器上,它可以表示的数值范围是-127到+128,故无法表示 197 和 198 ,需要转换。 但是,如果新类型是有符号的并且无法表示这个值,转换的结果要依赖于具体的编译器,甚至可能触发信号机制。即,C语言没有规定如何转换。 在很多平台上(显然包括楼主所在的机器环境),是直接把长度为 int 的 197 截断为 char 类型的长度。所以,最终它表示有符号数-59。
您好,非常感谢您的回复,我使用的编译器是VS2012。我是一个C语言的初学者,我对您的回复还有一些疑问,在您的回复中说到“在197和198这两个数值的二进制形式中,符号位似乎并不是1。”197 -->11000101 198 --> 11000110 直接转化成二进制的首位是否会直接成为符号位呢?烦请您帮忙把197到-59的过程详细说一下吗?[/quote] 对,我这两句话没说明白。 赋给 c1 和 c2 的值来自于常量 197 和 198 ,这两个常量的类型是 int 。所以,它们的最高位不是1,而是0。即,如果 int 类型的长度是 32 位,则 197 的二进制形式为 00000000000000000000000011000101 。把它截断为 char 类型的长度时,如果 char 类型的长度是 8,则截断后是 11000101 。
拜你所赐 2021-04-30
  • 打赏
  • 举报
回复
引用 3 楼 均陵鼠侠 的回复:
这是一个简单而又复杂的问题。 首先, %c 和 %d 都要求对应的变参是 int 类型。唯一不同的是,%c 是将这个 int 类型的变参转换为 unsigned char 类型的字符,然后予以显示,而 %d 则是将它转换为有符号十进制格式的数字字符予以显示。 其次,程序是没有问题的。尽管传入的变参是 char 类型的,但依照默认实参转换(default argument conversion)的规则,它是被转换为 int 类型之后传递给 printf 的。 最后,对于 printf 来说, %c 是将传入的值按 int 类型(的长度)取出,然后转换(缩小)为 unsigned char 类型(的长度),将它视为字符编码,然后打印这个字符; %d 是将传入的值按 int 类型(的长度)取出,拆分数位并转换为有符号十进制数字字符打印输出。这里的关键是, %d 要求这个转换过程必须区分数值的正负。这很好办,只需要判断其二进制形式的最高位(符号位)就可以了:为0是正数,为1是负数。然而,在197和198这两个数值的二进制形式中,符号位似乎并不是1。这就回到了开始:在将 char 类型的值转换为 int 类型并传递给 printf 时,是如何转换的?再往前,两个常量197和198的类型都是 int ,将它们赋给变量 c1 和 c2 时,需要从 int 转换为 char ,这个转换过程又是怎样的? 这就涉及到数值转换规则。首先,将一个整数类型的值转换为另一个除_Bool之外的整数类型时,如果这个值能够用新类型来表示,则转换后的值不变。 来看
char c1, c2;
c1 = 197;
c2 = 198;
在这里,如果 char 等价于 unsigned char ,那么,在主流的机器上,它可以表示的数值范围是 0到255,所以能够容纳,且 printf 不可能打印两个负值。显然,在楼主的环境下,char实际上是signed char。在主流的机器上,它可以表示的数值范围是-127到+128,故无法表示 197 和 198 ,需要转换。 但是,如果新类型是有符号的并且无法表示这个值,转换的结果要依赖于具体的编译器,甚至可能触发信号机制。即,C语言没有规定如何转换。 在很多平台上(显然包括楼主所在的机器环境),是直接把长度为 int 的 197 截断为 char 类型的长度。所以,最终它表示有符号数-59。
您好,非常感谢您的回复,我使用的编译器是VS2012。我是一个C语言的初学者,我对您的回复还有一些疑问,在您的回复中说到“在197和198这两个数值的二进制形式中,符号位似乎并不是1。”197 -->11000101 198 --> 11000110 直接转化成二进制的首位是否会直接成为符号位呢?烦请您帮忙把197到-59的过程详细说一下吗?
均陵鼠侠 2021-04-30
  • 打赏
  • 举报
回复
这是一个简单而又复杂的问题。 首先, %c 和 %d 都要求对应的变参是 int 类型。唯一不同的是,%c 是将这个 int 类型的变参转换为 unsigned char 类型的字符,然后予以显示,而 %d 则是将它转换为有符号十进制格式的数字字符予以显示。 其次,程序是没有问题的。尽管传入的变参是 char 类型的,但依照默认实参转换(default argument conversion)的规则,它是被转换为 int 类型之后传递给 printf 的。 最后,对于 printf 来说, %c 是将传入的值按 int 类型(的长度)取出,然后转换(缩小)为 unsigned char 类型(的长度),将它视为字符编码,然后打印这个字符; %d 是将传入的值按 int 类型(的长度)取出,拆分数位并转换为有符号十进制数字字符打印输出。这里的关键是, %d 要求这个转换过程必须区分数值的正负。这很好办,只需要判断其二进制形式的最高位(符号位)就可以了:为0是正数,为1是负数。然而,在197和198这两个数值的二进制形式中,符号位似乎并不是1。这就回到了开始:在将 char 类型的值转换为 int 类型并传递给 printf 时,是如何转换的?再往前,两个常量197和198的类型都是 int ,将它们赋给变量 c1 和 c2 时,需要从 int 转换为 char ,这个转换过程又是怎样的? 这就涉及到数值转换规则。首先,将一个整数类型的值转换为另一个除_Bool之外的整数类型时,如果这个值能够用新类型来表示,则转换后的值不变。 来看
char c1, c2;
c1 = 197;
c2 = 198;
在这里,如果 char 等价于 unsigned char ,那么,在主流的机器上,它可以表示的数值范围是 0到255,所以能够容纳,且 printf 不可能打印两个负值。显然,在楼主的环境下,char实际上是signed char。在主流的机器上,它可以表示的数值范围是-127到+128,故无法表示 197 和 198 ,需要转换。 但是,如果新类型是有符号的并且无法表示这个值,转换的结果要依赖于具体的编译器,甚至可能触发信号机制。即,C语言没有规定如何转换。 在很多平台上(显然包括楼主所在的机器环境),是直接把长度为 int 的 197 截断为 char 类型的长度。所以,最终它表示有符号数-59。

70,024

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧