1.求输出结果
//输出什么?
#include <stdio.h>
int main()
{
char a= -1;
signed char b=-1;
unsigned char c=-1;
printf("a=%d,b=%d,c=%d",a,b,c);
return 0;
}
解答:
int main()
{
char a = -1;
//-1
//10000000 00000000 00000000 00000001——原码
//11111111 11111111 11111111 11111110——反码
//11111111 11111111 11111111 11111111——补码,-1实际存储于计算机中的二进制形式
//a的类型为有符号字符型,故须将-1的补码进行截断,由低地址开始取8个bit位,得到
//11111111
signed char b = -1;
//b与a同理,得到
//11111111
unsigned char c = -1;
//c虽然为无符号数,但是其补码形式与有符号的-1仍然一致,区别在于如何解读补码(是否承认符号位)
//11111111 11111111 11111111 11111111
//截断后得到c的补码 :11111111 ——255(10进制)
//但是%d为有符号的int类型输出,所以需要将a,b,c整型提升为int
//a为有符号char 需按符号位(1)提升,提升后得到
//11111111 11111111 11111111 11111111——补码
//10000000 00000000 00000000 00000000——原码 -> -1(10进制)
//b同理 得到原码为-1
//c为无符号char,按0进行提升得到
//00000000 00000000 00000000 11111111——补码,正数的原反补相同,->255(10进制)
printf("a=%d,b=%d,c=%d", a, b, c);
return 0;
}
2.看看下面程序输出什么?
int main()
{
char a = -128;
printf("%u\n", a);
return 0;
}
解答:
int main()
{
char a = -128;
//-128
//10000000 00000000 00000000 10000000 ——原码
//11111111 11111111 11111111 01111111 ——反码
//11111111 11111111 11111111 10000000 ——补码
//随后截断 得到 10000000
//%u为无符号的int输出 ,则需将a先整型提升
//这里要注意,如何提升依据的是a的类型,而非输出的形式!
//a为有符号char,则需要根据符号位进行提升,得到
//11111111 11111111 11111111 10000000 (无符号的原反补码相同)
//然后以无符号整型的眼光看待这串数字
//得到4294967168(10进制)
printf("%u\n", a);
return 0;
}
3.求输出结果
int main()
{
char a = 128;
printf("%u\n",a);
return 0;
}
解答:
int main()
{
char a = 128;
//00000000 00000000 00000000 10000000 ——正数128的原反补码一致
//截断8个bit位得到 10000000
//a为有符号char,这里依然是按符号位提升为整型,得到
//11111111 11111111 11111111 10000000
//以无符号整型输出,故原反补码相同就无需将其转换为原码,结果与上题相同。
printf("%u\n", a);
return 0;
}
4.当一个符号数与无符号数相加
int main()
{
int i = -20;
unsigned int j = 10;
printf("%d\n", i + j);
return 0;
}
解答
int main()
{
int i = -20;
//-20
//10000000 00000000 00000000 00010100——原码
//11111111 11111111 11111111 11101011——反码
//11111111 11111111 11111111 11101100——补码
unsigned int j = 10;
//10
//00000000 00000000 00000000 00001010——原反补码相同
//-20+10:计算机内的计算均为补码的运算
//将两者的补码相加,得到
//11111111 11111111 11111111 11110110——补码
//我们以有符号int进行打印,则需将补码装换为原码
//10000000 00000000 00000000 00001010——原码 -10(10进制)
printf("%d\n", i + j);
return 0;
}
这里需要注意一个问题
,当一个无符号数与有符号数相加时,系统会以unsigned int的形式看待结果,而第4题则以%d的视角看待了这串补码,使其以带符号输出,可以看下面的代码,想一想输出的是什么?
int main()
{
int a = -20;
unsigned b = 10;
if ((a + b) > 0)
{
printf(">0");
}
else
{
printf("<0");
}
return 0;
}
这里的a+b视为无符号数,于是将补码直接视为原码,结果将是一串很大的数字
a+b的补码由第4题给出:11111111 11111111 11111111 11110110
可以看到十进制处的答案为4294967286
,这必然是大于0的
5.
求输出结果
int main()
{
unsigned int i;
for (i = 9; i >= 0; i--)
{
printf("%u\n", i);
}
return 0;
}
解答:
这是一个死循环,因为当i=0进入i–时,i 变为了-1,而 i 为无符号char,范围处于0~(2^32-1),实际上 i 变为了2 ^ 32-1,于是就进入了死循环。
6.
#include <stdio.h>
#include <string.h>
int main()
{
char a[1000];
int i;
for (i = 0; i < 1000; i++)
{
a[i] = -1 - i;
}
printf("%d", strlen(a));
return 0;
}
解答:
strlen函数为求字符串的长度,即计算字符’\0’(ascll值为0)前的字符的个数,那我们就看a数组何时到0。
这里要注意char能表达的数字的范围是-128~127.
a[0]= -1 补码:11111111
a[1]= -2 补码:11111110
…
…
a[127]= -128 补码:10000000
a[128]= 127 补码:01111111
…
…
a[254]=1 补码:00000001
a[255]=0 补码:0000000
负数有128个char,正数有127个char,长度为255.
7.
unsigned char i = 0;
int main()
{
for (i = 0; i <= 255; i++)
{
printf("hello world\n");
}
return 0;
}
解答:
unsigned char 的范围是0~255,当i=255 后执行i++,那么i就又返回到0,进入死循环,我们可以看下补码(无符号的原码和补码相同)
i=255 补码/原码:11111111
执行:i++
得到补码
1 00000000
unsigned char类型长度为1字节,需要截断
于是得到的补码为 00000000
=0(10进制)