我是C编程新手,我目前正在学习数据类型修订章节。在下面 程序,我的o / p是36,但编译器显示o / p 35.
main( )
{
char ch = 291 ;
printf ( "\n%d %c", ch, ch ) ;
}
任何人都可以解释为什么o / p即将到来35?我目前正在使用GCC 32位编译器。
答案 0 :(得分:8)
您的系统显然具有8位char
类型。这意味着291
太大而不适合 - 编译器将其模数减少256(2 8 ),最终得到35。
在这种情况下,Clang提供了一个很好的警告:
example.c:3:11: warning: implicit conversion from 'int' to 'char' changes value
from 291 to 35 [-Wconstant-conversion]
char ch = 291 ;
~~ ^~~
您应该避免依赖此行为,因为它可能因实现而异。 C99和C11规范(第6.3.1.3节)说明有符号整数转换:
否则,新类型已签名且值无法在其中表示;结果是实现定义的,或者引发实现定义的信号。
由于您正在使用GCC,您可能有兴趣阅读the documentation中的摘录:
当该值无法在该类型的对象中表示时,将整数转换为有符号整数类型的结果或引发的信号(C90 6.2.1.2,C99 6.3.1.3)
为了转换为宽度为N的类型,将该值减去模2 N 以在该类型的范围内;没有信号被提出。
在那里你有关于减少模256的完整解释。
答案 1 :(得分:3)
因为char
只能包含8位信息,而291需要的信息要多于要存储的信息。然后它将丢弃较高的位并仅保留变量中适合的值。
您可以通过按位和模块操作来模拟它:
291%256 = 35
291& 0xFF = 358位字符可以包含-128到127或0到255的值,具体取决于其是有符号还是无符号。
答案 2 :(得分:3)
你实际上是在泛滥。签名字符只能在8位字符系统(几乎无处不在)中从值-128到127(256值= 2 8 )。 所以我们选择一个实际的字符,其值等于291%256 = 35。
不要忘记第一个字符是0而不是1。
实际上,实际上是如何使用2's complement system表示字符:
unsigned
0 ------- 127 128 ------- 255
signed
0 ------- 127 -128 ------- -1
实际上,signed char c1 = -128
等于unsigned char c2 = 128
但是这里的问题无关紧要。我们讨论的是模数,因为只考虑了最后8位(如果内存中只有8位可用,那么另一位会被存储?)。
291 = % 1 0010 0011
(%
表示二进制表示)
它只保留等于% 0010 0011
的{{1}},并且无论您是否接受签名,都将被视为完全相同。