C语言day01-整数
一、C语言-整数内部表达
- 计算机内部一切都是二进制
- 18 ===>0001 0010
- 0 ===>0000 0000
- -18 ===>?
1.如何表示一个负数
- 十进制用“-”来表示负数,计算
12 + (-18) ==> 12 - 18 ==> -6 12 - (-18) ==> 12 + 18 ==> 30 12 * (-18) ==> -(12 * 18) ==> -216 12 / (-18) ==> -(12 * 18)
2.二进制负数
- 一个字节:
0000 0000 - 1111 1111 (0-255)
- 二进制表示负数方案
- 仿照十进制,设计特殊符号表示
- 取中间的数为0,如1000 0000(128)表示0,比它大的是正数,比它小的是负数
- 使用补码
3.补码
- 考虑-1,十进制中:-1 + 1 = 0
1 ==> (0000 0001); 0 ==> (0000 0000); ? + (0000 00001) = (0000 0000); ? ==> (1111 1111); (1111 1111) + (0000 0001) = (1 0000 0000); 八位,多出来的丢掉
- 因为 0 - (-1) = (-1),所以-1 = (1111 1111)
(1 0000 0000) - (0000 0001) = (1111 1111) 相当于==> 256 - 1 = 255 (1111 1111)被当作纯二进制看待时,是255,被当作补码是-1
- 补码的意义:拿补码和原码可以加出一个溢出的“零”;
- 扩展:对于 -a,其补码就是 0-a,实际就是2^n - a,n是位数;
二、C语言-整数范围
-
对于一个字节(8位),可以表达的是:
0000 0000 - 1111 1111
-
其中
0000 0000 --> 0; 1111 1111 ~ 1000 0000 --> -1 ~ -128; 0000 0001 ~ 0111 1111 --> 1 ~ 127;
1111 1111 ~ 1000 0000 --> -1 ~ -128; 高位为 “1”: 如果作为纯二进制数,是255 ~ 128; 如果作为补码,就是表示符号位,是-1 ~ -128;
-
实例:
int main(int argc, char const *argv[]) { char c = 255; int i = 255; printf("c = %d\n", c); //c = -1 printf("i = %d\n", i); //i = 255 return 0; }
char是1个字节,c --> 1111 1111;最高位是1,所以是个负数 int是4个字节,i --> 00000000 00000000 00000000 11111111;最高位为0所以为整数255;
1.unsigned
1111 1111 ~ 1000 0000 --> -1 ~ -128;
高位为 “1”:
如果作为纯二进制数,是255 ~ 128;
如果作为补码,就是表示符号位,是-1 ~ -128;
如果一个字面量常数想要表达自己是unsigned,可以在后面加u或者U
- 255U
int main(int argc, char const *argv[]) { char c = 255; unsigned char c1 = 255; printf("char c = %d\n", c); //char c = -1 printf("unsigned char c1 = %d\n", c1); //unsigned char c1 = 255 return 0; }
unsigned 不以补码的形式,就是纯二进制,最高位的1不代表负号;
- unsigned的设计初衷并不是扩展正数部分表达的范围,而是为了做纯二进制的运算,主要是为了移位。
2.整数越界
- 整数以纯二进制方式进行计算的,所以:
1111 1111 + 1 --> 1 0000 0000 --> 0 0111 1111 + 1 --> 1000 0000 --> -128 1000 0000 - 1 --> 0111 1111 --> 127
2.整数越界
- 整数以纯二进制方式进行计算的,所以:
1111 1111 + 1 --> 1 0000 0000 --> 0 0111 1111 + 1 --> 1000 0000 --> -128 1000 0000 - 1 --> 0111 1111 --> 127
三、C语言-格式化输入输出
整型:char,short,int,long,long long
在所输入输出时只用int
或者long long
- %d:
char
,short
,int
(10进制打印) - %ld:
long
,long long
- %u:
unsigned
- %lu:
unsigned long long
例 1:
int main(int argc, char const *argv[])
{
char c = -1;
int i = -1;
printf("c = %u\n", c);
printf("i = %u\n", i);
return 0;
}
输出:
c = 4294967295
i = 4294967295
分析:
char c = -1; 11111111
int i = -1; 11111111 11111111 11111111 11111111
i 和 c 作为printf的参数,编译器会把自动转换为int类型;
因为是有符号的所以扩展到全部位上都是1;
有因为“%u”以unsigned打印,所以4294967295
8进制和16进制
- 一个以
0
开始的数字字面量是8进制 - 一个以
0x
开始的数字字面量是16进制 - 16进制很适合表达二进制数据,因为4位2进制正好是一个16进制
- 8进制的一位数字正好表达3位二进制
* 实例2:
int main(int argc, char const *argv[])
{
char c = 012;
int i = 0x12;
printf("c = %d\n", c);
printf("i = %d\n", i);
return 0;
}
输出:
c = 10
i = 18
* 实例3:
int main(int argc, char const *argv[])
{
char c = 012;
int i = 0x12;
printf("八进制c = %o\n", c);
printf("十进制i = %x\n", i);
return 0;
}
输出:
八进制c = 12
十进制i = 12
四、整型的选择
- 为什么整型分那么多种;
- 为了准确表达内存,做底层程序的需要
- 没有特殊需求就选择int
- 现在的CPU的字长普遍是32位或64位,一次内存读写就是一个int,一次计算也是一个int,选择更短的类型不会更快,甚至更慢
- 现代的编译器一般会设计内存对齐,所以更短的类型实际在内存中可能也占据一个int的大小
- unsigned与否只是输出的不同,内部计算还是一样的。