Linux C编程风格
基本数据类型
整型:123,0123,0x123ff
浮点型:3.14,3.14e3,3.14E-2
字符型常量和字符串型常量
字符:a,\0,\n
字符串:a,hello word
布尔类型_Bool、bool
逻辑值true(真)和false(假),因为C用值1表示true,用值0表示false,所以_Bool类型实际上也是一种整数类型。非0即真
不同系统表达的范围不一样
Void型
关键字void用来修饰指针变量、函数返回类型和函数参数
Void *p 表示是通用型指针,不能修饰变量
Void f() 表示没有返回值
Int main(void) 表示函数没有参数
整数的存储问题
整数在计算机内是如何保存?
二进制补码形式
正整数:
正数的补码就是其远吗本身。
原码: 就是吧相应的数值转换成二进制形式
例子:
13 :
00000000 00000000 00000000 00001101 <- 13的原码,也是13的补码
9 : 8bits
9 = 8 + 1
0000 1001
int a = 9;
a :
00000000 00000000 00000000 00001001
负整数:
负数的补码 = 绝对值的原码 取反 + 1
负数的补码 => -1 => 取反 => |负数| => 负数
-13 :
|-13| :00000000 00000000 00000000 00001101
取反 : 11111111 11111111 11111111 11110010
+1 : 11111111 11111111 11111111 11110011 <- -13的补码形式
一个有趣现象,假设 8bits来保存一个正数:
-2的存放形式是什么?
254的存放形式是什么?
1111 1110
-3的存放形式是什么?
253的存放形式是什么?
1111 1101
-4的存放形式是什么?
252的存放形式是什么?
1111 1100
.......
结论1:
一个负整数会和一个比较大的正整数的补码形式一样。
-x 和 (2^n - x) 一样
2^n : 笔记中表示2的n次幂
n : 用多少个bit来存储一个正数
假设:
n = 16
-17 和 2^16 - 17
结论2:
CPU内部是没有符号位的概念,对于CPU来说,所有bit位,
都是数值位,都参与运算。至于是有符号的,还是无符号的数,
就得看编译器的词义啦(意思是说,你把它当做是一个有符号的
还是一个无符号的数。)
//char a ;
a : 1111 1110
printf("%d\n", a); // -2
printf("%u\n", a); // 254
练习:
1. 假设计算机中,用8bits来存储一个正数,
已知某个正数在计算机中的存放形式如下:
a : 10001000
请问这个整数值是多少呢?
136 / -120
到底是136还是-120?
关键是看(CPU,编译器)把它当做是一个有符号的数,
还是一个无符号的数。
printf("%u\n",a ); //136
10001000
所有的bits都是数值位
=> 136
printf("%d\n",a ); //-120
10001000
符号位 数值位
1 -> 负数
0 -> 正数
逆运算
补码 =====> 负数
-1 => 取反 => |负数|
补码: 10001000
-1 :10000111
取反: 01111000
|负数|: 120
负数 : -120
2. 分析如下程序的输出结果
int a = -2;
printf("%d\n", a); //-2
printf("%u\n", a); //2^32 - 2
解题:
a : 11111111 11111111 11111111 11111110
%d : 有符号的数 符号位 -> 1
负数的补码 : 11111111 11111111 11111111 11111110
-1 : 11111111 11111111 11111111 11111101
取反 : 00000000 00000000 00000000 00000010
|负数| : 2
负数: -2
%u : 无符号的数
直接算出 : 11111111 11111111 11111111 11111110
=> 2^32 - 2
3. 分析如下程序的输出结果
int a = -56;
printf("%d\n", a); //-56
printf("%u\n", a); //2^32 -56
4. 分析如下程序的输出结果
unsigned int a = -1u;
printf("%d\n", a); // -1
printf("%u\n", a); // 2^32 - 1
解题:
a : -1u
a : 11111111 11111111 11111111 11111111
%d : 有符号的数, 看符号位 => 1
负数: “逆运算” => -1
%u : 无符号的数
直接运算: 2^32 - 1
5. 分析如下程序的输出结果
int a = 1 << 31;
printf("%d\n", a); //-2^31
printf("%u\n", a); // 2^31
1 : 00000000 00000000 00000000 00000001
1 << 31 : 1 00000000 00000000 00000000 0000000
a : 10000000 00000000 00000000 00000000 <- a的内容
%d : 10000000 00000000 00000000 00000000
1 - 负数
逆运算:
-1 : 01111111 11111111 11111111 11111111
取反:10000000 00000000 00000000 00000000
|负数|: 2^31
负数: -2^31
%u : 10000000 00000000 00000000 00000000
直接运算: 2^31
整数之间的赋值的问题
在C语言中,允许不同类型的整数之间相互赋值。
char -> int
int -> long
long -> short
....
unsigned int -> unsigned char
....
有一个问题: 不同类型的整数,存储空间大小都不一样。
char 8bits
short 16bits
这个问题该怎么解决呢?
C语言标准建议:
(1) 长 -> 短
长的赋值给短的,低字节直接拷贝,
高字节全部discard舍弃,也没有办法要啦。
int -> short
int -> char
short -> char
......
(2) 短 -> 长
短的赋值给长的,低字节直接拷贝,
长的高字节补什么呢?
如果短的那个数是无符号的数,高位就全部都补0;
如果短的那个数是有符号的数,高位就全部都补 符号位。
例子:
char c = 250;
char d;
d = c + 8;
printf("%d\n", d);
printf("%u\n", d);
解题:
c :11111010
d : xxxxxxxx
d = c + 8 :
c -> int : 短 -> 长
11111111 11111111 11111111 11111010
8:
00000000 00000000 00000000 00001000
-------------------------------------------
100000000 00000000 00000000 00000010
int => char : 长 -> 短
char d : 00000010
char d => int/unsigned int :
00000000 00000000 00000000 00000010 <- 在打印之前,计算机中最终存放形式
%d(signed int):
符号位: 0 - 正数
=> 2
%u(unsigned int) :
直接运算:
=> 2
练习:
1.分析如下程序的输出结果
unsigned char c = 250;
char d;
d = c + 8;
printf("%d\n", d);
printf("%u\n", d);
分析:
c : 11111010
d = c + 8 :
c -> int : 00000000 00000000 00000000 11111010
8 : 00000000 00000000 00000000 00001000
-----------------------------------------------
00000000 00000000 00000001 00000010
d 长 -> 短: 00000010
char d => int/unsigned int :
00000000 00000000 00000000 00000010
%d : 2
%u : 2