跳转至

2. C 语言的基本数据类型

2.1 进位计数制

一个 \(r\) 进制数中,第 \(k\) 位的位权是 \(r^k\)。二进制转八进制时每 3 位一组,转十六进制时每 4 位一组,这比先转十进制省事。

  • 十进制整数转 \(r\) 进制:除 \(r\) 取余,余数逆序排列;
  • 十进制小数转 \(r\) 进制:乘 \(r\) 取整,整数部分顺序排列;
  • \(r\) 进制转十进制:各位数字乘相应位权后求和。

有些十进制小数换成二进制会变成无限小数,所以浮点计算会带一点舍入误差。判断两个浮点数“相等”时,一般看误差是否足够小,不要想当然地直接用 ==

2.2 整数在计算机中的表示

这几个概念容易混,按转换顺序记:原码 \(\rightarrow\) 反码 \(\rightarrow\) 补码。负数原码的最高位是 1;求反码时符号位不动,其余位取反;反码再加 1 就是补码。正数的三种表示相同。

机器里实际用补码存有符号整数。这样加减法可以共用一套运算规则,0 也只有一种表示。

偏移码可以由补码把符号位取反得到,正数最高位为 1,负数最高位为 0。浮点数的阶码就是用偏移码保存的。

定点数的小数点位置固定;浮点数则把数写成类似科学计数法的形式。课件按 IEEE 754 讲 floatdouble:一段存符号,一段存带偏移的阶码,剩下的存尾数。因此浮点数能表示很大的范围,但有效数字有限。

\(n\) 位整数:

  • 无符号数范围为 \(0\sim 2^n-1\)
  • 二进制补码有符号数范围为 \(-2^{n-1}\sim 2^{n-1}-1\)

int 不一定永远是 32 位,具体大小看平台,可以用 sizeof<limits.h> 查。无符号整数溢出后按模 \(2^n\) 回绕;有符号整数溢出不能这样推结果。

2.3 基本类型、常量与变量

基本类型先按下面这几类记:

  • 整型:charshortintlonglong long,以及对应的 unsigned 类型;
  • 浮点型:floatdoublelong double
  • 空类型:void

常量的常见写法:

42          /* 十进制整数 */
052         /* 八进制整数,等于十进制 42;08 不是合法八进制常量 */
0x2A        /* 十六进制整数 */
42U         /* unsigned int */
42L         /* long */
3.14        /* double */
3.14f       /* float */
2.5e-3      /* 科学计数法 */
'A'         /* 字符常量 */
"A"         /* 字符串,占两个 char:'A' 和 '\0' */

转义字符包括 \n(换行)、\t(制表)、\\(反斜杠)、\'\"\0。字符在计算中按其字符编码值参与整型运算,如 '7' - '0' 得到整数 7

变量先定义再使用。全局变量和静态变量没有手动给初值时会被置 0;普通局部变量不会,刚定义就拿来算通常会得到乱值。

const double pi = 3.141592653589793;
unsigned long count = 0UL;
char grade = 'A';

const 表示不通过这个名字修改对象。它和宏常量不是一回事:const 变量有明确类型,也受作用域限制。

2.4 sizeof 与类型转换

sizeof 算一个类型或对象占多少字节,写成 sizeof(类型)sizeof 表达式。有个容易出现在读程序题里的细节:sizeof(i++) 只看 i 的类型,并不会真的执行 i++

不同类型混在一个表达式中时,会先按类型等级自动转换;赋值时还要再转成左边变量的类型。最常考的是整数除法:

double x = 5 / 2;          /* 先做整数除法,x 为 2.0 */
double y = 5.0 / 2;        /* y 为 2.5 */
int n = (int)3.8;          /* 强制转换,截去小数部分,n 为 3 */

强制类型转换只管这一次计算,原变量的类型并没有变。

评论