C 语言的数据类型有很多,可以分为 4 大类型:
void 类型 基本类型 字符类型 有符号整数类型 无符号整数类型 浮点类型 枚举类型 派生类型 数组类型 结构体类型 联合体类型(也叫共同体类型) 函数类型 指针类型
一、基本类型
有符号整数类型
char
(等价类型:signed char
)short
(等价类型:signed short
、short int
、signed short int
)int
(等价类型:signed int
、signed
)long
(等价类型:signed long
、long int
、signed long int
)(C99 起)long long
(等价类型:signed long long
、long long int
、signed long long in
t`)(C99 起)无符号整数类型
unsigned char unsigned short(等价类型: unsigned short int
)unsigned int(等价类型: unsigned
)unsigned long(等价类型: unsigned long int
)(C99 起)unsigned long long(等价类型: unsigned long long int
)(C99 起)字符类型
char浮点类型
floatdoublelong double
1.1. 整数类型
1.1.1. 整数类型大小
C 标准规定
1 == sizeof(char)
<= sizeof(short)
<= sizeof(int)
<= sizeof(long)
<= sizeof(long long)
1.1.2. 数据模型
关于基本类型大小的是实现方案,统称为:数据模型。有 4 种常见的数据模型
32bit 系统(指针为 32 位)
Win32 API Unix、类 Unix 系统(Linux、Mac OS X) Win16 API LP32 ILP32 64bit 系统(指针为 64 位)
Unix、类 Unix 系统(Linux、Mac OS X) Win64 API LLP64 LP64 比较少见的数据模型
仅出现在早期 64 位 Unix 系统(例如 Unicos on Cray) ILP64:int、long、指针均为 64 位

1.1.3. 有符号整数类型和无符号整数类型区别
整数类型可分为:有符号整数类型、无符号整数类型。
1.1.4. 有符号整数 char、无符号整数 unsigned char
// 0xBD <=> 0b10111101
char c1 = 0xBD;
unsigned char c2 = 0xBD;
printf("%d %d", c1, c2); // 输出:-67 189

// 0x43 <=> 0b01000011
char c1 = 0x43;
unsigned char c2 = 0x43;
printf("%d %d", c1, c2); // 输出:67 67

c1、c2 变量在内存中存放的二进制数据是完全一样的; 对于同一份二进制数据,分别以有符号数形式、无符号数形式解读出来的含义可能是不一样的。
1.1.5. 整数的取值范围
char
、unsigned char
都只占用一个字节,能够存放的二进制数据范围都是[0b0000 0000, 0b1111 1111]
。
char
的取值范围:unsigned char
的取值范围:有 n 个二进制位的有符号数的取值范围 有 n 个二进制位的无符号数的取值范围
| 位数 | 符号 | 最小值 | 最大值 |
|---|---|---|---|
| 8 | 有符号 | ||
| 8 | 无符号 | 0 | |
| 16 | 有符号 | ||
| 16 | 无符号 | 0 | |
| 32 | 有符号 | ||
| 32 | 无符号 | 0 | |
| 64 | 有符号 | ||
| 64 | 无符号 | 0 |
1.1.6. 溢出(Overflow)
溢出指的是内容超过了已知容器的容量。
例:short s;
short
类型的变量 s 有 2 个字节的内存空间如果要将超过 2 个字节(比如 4 个字节)的数据存储到变量 s 中去,就会产生内存溢出
案例一:
int i = 16909292;
short s = 16909292;
char c = i;
printf("%d\n", i); // 输出:16909292
printf("%d\n", s); // 输出:1004
printf("%d\n", c); // 输出:-20

当出现溢出时,会优先保留低字节的数据,舍弃高字节的数据; 所以在给取值范围小的变量赋值时要注意防止数据溢出,否则结果可能会跟预期不符合。
思考:那是不是以后都统一使用取值范围比较大的变量就好了?应该根据已知的数据范围选择合适大小的变量,不然会造成内存空间的浪费
案例二:
int i = 16909292;
char c = i;
i = c;
printf("%d\n", i); // 输出:-20
printf("%d\n", c); // 输出:-20

案例三:
unsigned char c1 = 255;
char c2 = -1;

c1 = c1 + 1;
c2 = c2 + 1;
printf("c1=%d, c2=%d", c1, c2); // 输出:c1=0, c2=0

案例四:
unsigned char c1 = 0;
char c2 = 0;

c1 = c1 - 1;
c2 = c2 - 1;
printf("c1=%d, c2=%d", c1, c2); // 输出:c1=255, c2=-1

案例五:
unsigned char c1 = 127;
char c2 = 127;

c1 = c1 + 1;
c2 = c2 + 1;
printf("c1=%d, c2=%d", c1, c2); // 输出:c1=128, c2=-128

案例六:
unsigned char c1 = 128;
char c2 = -128;

c1 = c1 - 1;
c2 = c2 - 1;
printf("c1=%d, c2=%d", c1, c2); // 输出:c1=127, c2=127

案例七:
unsigned char c1 = 255;
char c2 = -1;

c1 = c1 + 1;
c2 = c2 + 1;
printf("c1=%d, c2=%d", c1, c2); // 输出:c1=0, c2=0

案例八:
unsigned char c1 = 0;
char c2 = 0;

c1 = c1 - 1;
c2 = c2 - 1;
printf("c1=%d, c2=%d", c1, c2); // 输出:c1=255, c2=-1

1.1.7. unsigned char、char 的取值范围

1.2. 浮点类型
浮点类型可以用来表示小数(比如 3.14),包括float
,double
,long double
类型
最常用的浮点类型是float
和double
,一般在数值后面加上 f 或者 F 表示十 float 类型的数值
float f = 3.14F;
double d = 10.24;
printf("%f %f", f, d); // 输出:3.140000 10.240000
float
:单精度(Single)浮点类型,占用 32bit,可以保证精确到小数点后 6 位最小值: 最大值: double
:双精度(Double)浮点类型,占用 64bit,可以保证精确到小数点后 15 位最小值: 最大值:
1.2.1. 浮点类型的存储细节
思考:为什么 32bit 的
unsigned int
最大值是 2^32-1,而 32bit 的float
最大值是 3.4 * 10^38?因为他们的存储方式不一样,浮点数在计算机中是按照 IEEE 754 标准存储的。


1.3. 整数、浮点数字面量
char c = 10;
unsigned char uc = 10;
short s = 10;
unsigned short us = 10;
int i = 10;
unsigned int ui1 = 10u;
unsigned int ui2 = 10U;
long l1 = 10l;
long l2 = 10L;
unsigned long ul1 = 10ul;
unsigned long ul2 = 10UL;
// 不能是lL或Ll
long long ll1 = 10ll;
long long ll2 = 10ll;
float f1 = 10.24F;
double d1 = 10.24;
// 小数部分可选:1.0
float f2 = 1.F;
double d2 = 1.;
// 整数部分可选:0.1
float f3 = .1F;
double d3 = .1;
// 十进制小数 1.2 * 10^3 = 1200.0
float f4 = 1.2e3F; // 1.2E3F
double d4 = 1.2e3; // 1.2E3
// 十六进制小数 1.125 * 2^10 = 1152.0
float f5 = 0x1.2p10F; // 0x1.2P10F
double d5 = 0x1.2p10; // 0x1.2P10
// 十进制 1.875 * 2^3 = 15.0
printf("%f", 0x1.ep+3); // 可写:0x1.EP+3 输出:15.000000
// 十进制 1.875 * 2^(-2) = 0.46875
printf("%f", 0x1.ep-2); // 可写:0x1.EP-2 输出:0.468750
int v 0xE+2; // 错误
int x = 0xe+2; // 错误
int y = 0xA+2; // OK
int z = 0xE +2; // OK
int q = (0xE)+2 // OK
1.4. printf 中的转换格式指定符

1.4.1. 案例一
printf("%zd\n", sizeof(int)); // 输出:4
long long age = 10LL;
printf("%lld\n", age); // 输出:10
unsigned long no = 8UL;
printf("%lu\n", no); // 输出:8
char *name = "idbeny";
char *place = "1024星球";
printf("我是%s,欢迎来到%s\n", name, place); // 输出:我是idbeny,欢迎来到1024星球
1.4.2. 案例二
// 用%%来显示一个%
printf("%d%%%d\n", 10, 20); // 输出:10%20
int i1 = 10;
// %6d表示占用6个字符位置,默认靠右对齐(左边空白)
printf("welcome%6d24星球\n", i1); // 输出:welcome 1024星球
// %-6d表示占用6个字符位置,靠左对齐(右边空白)
printf("welcome%-6d24星球\n", i1); // 输出:welcome10 24星球
int i2 = -6;
// %+6d:加号(+)表示显示正负号
printf("%+6d和%+-6d\n", i1, i2); // 输出: +10和-6
double d = 3.1415926;
// 四舍五入保留2位小数
printf("%.2f\n", d); // 输出:3.14
/*
* 占用10个字符位置
* 四舍五入保留4位小数
* 显示正负号
* 靠左对齐
*/
printf("1%+-10.4f2\n", d); // 输出:1+3.1416 2
1.5. scanf 中的转换格式指定符
// 用%%来匹配一个%
int age = 10;
scanf("%%%d", &age); // 输入:%30
printf("age is %d\n", age); // 输出:age is 30
/*
输入:30
输出:age is 10
输入:%30
输出:age is 30
*/
// 在scanf中,float类型用%f
float f;
scanf("%f", &f);
// 在scanf中,double类型用%lf
double d;
scanf("%lf", &d);
// 在printf中,float、double都可以用%f、%lf
printf("%f %lf %f %lf", f, f, d, d);
/*
输入:10(回车)20
输出:10.000000 10.000000 20.000000 20.000000
*/
int i1 = 1;
int i2 = 2;
// %*3d是跳过长度为3的整数
scanf("%2d%*3d%4d", &i1, &i2);
printf("i1=%d,i2=%d", i1, i2);
/*
输入:10 20 40
输出:i1=10,i2=40
输入:10111140
输出:i1=10,i2=140
*/
1.6. 类型转换
格式:
类型1 v1 = xx;
类型2 v2 = (类型1)v1;
案例:
char c = 'A';
int i = (int)c;
printf("%d\n", i); // 输出:65
int i2 = 200;
short s = (short)i2;
printf("%d\n", s); // 输出:200
// 会丢失精度
double d = 3.14;
int i3 = (int)d;
printf("%d\n", i3); // 输出:3
int i4 = 333;
double d2 = (double)i4;
printf("%f\n", d2); // 输出:333.000000
其实在很多时候,编译器都会进行隐式类型转换:
char c = 'A';
int i = c;
printf("%d\n", i); // 输出:65
int i2 = 200L;
short s = i2;
printf("%d\n", s); // 输出:200
double d = 3.14;
int i3 = d;
printf("%d\n", i3); // 输出:3
int i4 = 333;
double d2 = i4;
printf("%f\n", d2); // 输出:333.000000
大类型转小类型的时候,可能会丢失精度:
double d = 3.14;
printf("%f\n", d); // 输出:3.140000
int i = d;
printf("%d\n", i); // 输出:3
double d2 = 1.1234567890123456789123;
printf("%.20f\n", d2); // 输出:1.12345678901234569125
float f = d2;
printf("%.20f\n", f); // 输出:1.12345683574676513672

文章转载自1024星球,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




