🌈write in front :
🔍个人主页 : @啊森要自信的主页
✏️真正相信奇迹的家伙,本身和奇迹一样了不起啊!
欢迎大家关注🔍点赞👍收藏⭐️留言📝>希望看完我的文章对你有小小的帮助,如有错误,可以指出,让我们一起探讨学习交流,一起加油鸭。
文章目录
- 前言
- 一、数据类型
- 1.1字符型
- 1.2 整型
- 1.3 浮点型
- 1.4 布尔类型
- 二、各种数据类型的⻓度
- 2.1 sizeof操作符
- 2.2 数据类型⻓度
- 2.3 sizeof中表达式不计算
- 三、signed 和 unsigned
- 四、数据类型的取值范围
- 总结
前言
一、数据类型
C语言主要的数据类型和变量的数据类型有:
- 基本数据类型:
-
整数类型:
char
:字符类型,占1字节short
:短整型,占2字节int
:整型,占4字节long
:长整型,占4或8字节long long
:更长的整型,占8字节
-
浮点数类型:
float
:单精度浮点数,占4字节double
:双精度浮点数,占8字节
-
其他类型:
void
:无类型bool
:布尔类型C语言没有内置布尔类型bool,需要包含<stdbool.h>
头文件
- 变量的数据类型:
- 自动变量:定义在函数或代码块内的变量,生命周期在函数或代码块结束后结束。
- 静态变量:使用static声明的变量,生命周期持续整个程序执行期间。
- 寄存器变量:使用
register
声明,让变量存储在CPU寄存器
中加快访问速度。- 外部变量:使用
extern
声明的变量定义在其他源文件中。- 指针变量:用于存储地址的值。
- 数组变量:用于存储多个同类型数据元素。
- 结构体变量:用于存储不同类型数据元素的集合。
- 联合体变量:用于
存储占用相同内存空间
的不同类型数据。- 枚举变量:用于定义一组相关常量的值。
#include <stdio.h>
#include <stdbool.h>
int main()
{
// 基本数据类型
char ch = 'a'; // 字符类型
short num = 10; // 短整型
int age = 25; // 整型
long long bigNum = 1000000000; // 长长整型
// 浮点数类型
float price = 19.99; // 单精度浮点
double weight = 75.123; // 双精度浮点
// 其他类型
void func(); // 无类型
bool isMale = true; // 布尔类型
// 变量的数据类型
static int count = 0; // 静态变量
register int loop = 0; // 寄存器变量
int* pNum = &age; // 指针变量
int arr[10]; // 数组变量
struct Student
{
char name[20];
int id;
} stu; // 结构体变量
union Data
{
int x;
char c;
} data; // 联合体变量
enum Color { RED, GREEN, BLUE }; // 枚举变量
printf("char: %c, short: %d, int: %d\n", ch, num, age);
return 0;
}
1.1字符型
char
[signed] char
unsigned char
1.2 整型
//短整型
short [int]
[signed] short [int]
unsigned short [int]
//整型
int
[signed] int
unsigned int
//⻓整型
long [int]
[signed] long [int]
unsigned long [int]
//更⻓的整型
//C99中引⼊
long long [int]
[signed] long long [int]
unsigned long long [int]
1.3 浮点型
float
double
long double
1.4 布尔类型
C语⾔其实原来并没有为布尔值单独设置⼀个类型,⽽是使⽤整数0
在
表示假,非零表示真。在C99
中也引⼊了布尔类型,是专⻔表⽰真假的。
布尔类型的使⽤得包含头⽂件 <stdbool.h>
布尔类型变量的取值是:true或者false.
#define bool _Bool
#define false 0
#define true 1
用代码展示
_Bool flag = true;
if (flag)
printf("i like C\n");
二、各种数据类型的⻓度
2.1 sizeof操作符
C语言中的sizeof
操作符用来计算数据类型或表达式所占用的内存字节数。
sizeof主要有以下几种用法:
- 计算数据类型大小
sizeof(类型名)
例如:
sizeof(int) // 4
sizeof(char) // 1
- 计算数组元素个数
sizeof(数组名) / sizeof(数组元素类型)
例如:
- 计算结构体大小
sizeof(结构体名)
例如:
- 计算表达式大小
sizeof(表达式)
例如:
C语言标准只规定
sizeof
运算符返回一个无符号整数,但并没有明确指定返回值的具体类型。
这就可能导致程序的可移植性问题:
-
不同系统下,
sizeof
返回值类型可能不同,使用不当类型的格式化输出可能会出错,返回值的类型有可能是unsigned int
,也有可能是unsigned long
,甚⾄是unsigned long long
,对应的printf()
占位符分别是%u
、%lu
和%llu
。 -
需要存储
sizeof
结果的变量也需要使用正确的类型,否则可能会溢出或截断。
C语言提供了size_t
类型来解决这个问题:
-
size_t
是一个类型别名,它会被定义为当前系统下sizeof
返回值的正确类型,可能是unsigned int
、unsigned long
等。 -
程序使用
size_t
来存储和操作sizeof
结果,就可以保证类型安全且可移植。 -
格式化输出时使用%zd,它会自动匹配size_t类型。
#include <stdio.h>
int main()
{
int a = 10;
printf("%zd\n", sizeof(a));
printf("%zd\n", sizeof a);//a是变量的名字,可以省略掉sizeof后边的()
printf("%zd\n", sizeof(int));
printf("%zd\n", sizeof(6 + 8.8));
return 0;
}
2.2 数据类型⻓度
您总结得很好,我重新梳理一下C语言主要数据类型的长度:
char
: 1字节short
: 2字节int
: 32/64位系统通常为4字节long
: 4字节long long
: 8字节float
: 4字节double:
8字节void*
: 与系统地址长度相同,32位系统为4字节,64位系统为8字节- size_t: 与系统地址长度相同,用来表示sizeof()函数返回值的类型
在 X86
配置下的输出:
在 X64
配置下的输出:
2.3 sizeof中表达式不计算
sizeof运算符计算的不是表达式的值,而是类型的大小。
更准确地说,sizeof
运算符返回它操作数类型的大小,单位为字节。
如果操作数是一个类型
,那么它直接返回该类型的大小;
如果操作数是一个表达式
,那么它返回表达式类型的大小。
举个例子:
int main()
{
int a = 10;
int b = 20;
short s = 2;
int c = 30;
printf(" %zd\n", sizeof(int)); // 返回int类型大小,如4字节
printf(" %zd\n", sizeof(a)); // 返回int类型大小,如4字节,和sizeof(int)相同
printf(" %zd\n", sizeof(a + b)); // 返回int类型大小,如4字节,计算a + b的类型是int
printf(" %zd\n", sizeof(s = c + 1));
printf("s = %d\n", s);
return 0;
}
在sizeof(a + b)中:
-
a + b是一个表达式,计算结果是int类型
-
sizeof不计算a + b的实际值,而是直接返回其类型int的大小
-
sizeof(s = c + 1)
s = c + 1
是一个赋值表达式,计算c+1的值,结果是int类型- 但赋值的对象是
short
类型变量s
- 所以
sizeof
返回short
类型的大小,即2
字节
-
sizeof
返回类型大小,不计算表达式值 -
表达式计算和赋值可能涉及类型转换
sizeof
在代码进⾏编译的时候,就根据表达式的类型确定了,类型的常⽤,⽽表达式的执⾏却要在程序运⾏期间才能执⾏,在编译期间已经将sizeof
处理掉了,所以在运⾏期间就不会执⾏表达式了。
三、signed 和 unsigned
signed
和unsigned
关键字用于指定整数类型的符号:
-
signed: 有符号整数类型,可以表示正数和负数。默认情况下所有整数类型(char、short、int、long)都是
signed
的。 -
unsigned
: 无符号整数类型,只能表示非负整数,范围比signed类型更大。
主要区别:
-
存储表示:
-
signed
类型用二进制最高位表示数值的符号,正数为0
,负数为1
。 -
unsigned
类型最高位都是数值本身,不表示符号。
-
-
数值范围:
-
signed
类型的范围依赖于其位宽,如int为-2147483648到2147483647。 -
unsigned类型没有符号位,所以范围比signed类型更大,如uint为0到4294967295。
-
-
运算结果:
-
signed
类型在一些运算中可能会发生溢出。 -
unsigned
类型不会发生溢出,超出范围直接循环回到最小值。
-
小例子:
#include <stdio.h>
int main()
{
unsigned int a = 10;
signed int b = 10;
a -= 20;
b -= 20;
printf("a = %zu\n", a);
printf("b = %zd\n", b);
return 0;
}
第一种分析:
- a为
unsigned int
,范围0-4294967295
- a原值为10,减20后为-10
- 但unsigned int没有负数表示,所以-10会溢出计算为最大值4294967295
- b为
signed in
t,范围-2147483648-2147483647
- b原值为10,减20后为-10
- -10正好在
signed int
范围内,所以结果正确输出为-10
- 这里
unsigned int
和signed int
在减法溢出后的表现不同:unsigned int
溢出后取最大正值signed int
保留数值的符号,输出负数
所以这个例子更清晰地展示了signed和unsigned类型在溢出情况下的区别。
二进制重新解释这道题:
题目中有两个变量:
-
unsigned int a
,其范围为0-4294967295
-
signed int b
,其范围为-2147483648-2147483647
开始时:
a = 10
b = 10
然后执行:
a -= 20
b -= 20
分析:
- 对于a来说,它是
unsigned int
类型,没有负数表示。
当a-=20时,正确的二进制计算是:
a原值: 0000 0000 0000 0000 0000 0000 0000 1010 (10)
a-=20: 0000 0000 0000 0000 0000 0000 0000 0110 (-10,但unsigned int没有负数)
由于结果-10
超出了unsigned int
的范围,所以根据无符号溢出规则,高位溢出位被舍弃,结果保留为最大正值:
0000 0000 0000 0000 0000 0000 0000 0110 溢出为4294967295
- 对于
b
来说,它是signed int
类型,可以表示负数。
当b-=20时,二进制计算是:
b原值: 0000 0000 0000 0000 0000 0000 0000 1010 (10)
b-=20: 1111 1111 1111 1111 1111 1111 1111 1010 (-10)
-10
处于signed int
的有效范围内,所以结果直接输出-10
。
总之,通过这个例子可以清晰地看出:
unsigned int
在溢出时结果取最大正值signed int
根据符号位判断正负,直接输出结果
四、数据类型的取值范围
C语言主要的数据类型和其取值范围如下:
用二进制来解释C语言主要数据类型的取值范围:
它的高位为符号位:0表示正数,1表示负数。
char
- 1字节,表示为8位二进制
- 高位为符号位,0表示正数,1表示负数
- 所以取值范围是:0xxx xxxx ~ 0111 1111,即0~ 127为正数,-128 ~ -1为负数
unsigned char
- 也是1字节8位二进制
- 但没有符号位,所以全为数据位
- 取值范围是:0000 0000 ~ 1111 1111,即0~255
short
- 2字节,表示为16位二进制
- 高位为符号位,0表示正数,1表示负数
所以取值范围是:0xxx xxxx xxxx xxxx ~ 0111 1111 1111 1111,
即0~ 32767为正数,-32768~ -1为负数 (这里的"xxx"代表低15位可以是0或者1,也就是数据位。)
unsigned short
- 也是2字节16位二进制
- 没有符号位,所以全为数据位
- 取值范围是:0000 0000 0000 0000 ~ 1111 1111 1111 1111,即0~65535
总结
以上归纳了C语言主要的数据类型分类,获取数据类型长度的方法,signed
和unsigned
的区别,以及各种数据类型在不同情况下的取值范围范围。感谢你的收看,如果文章有错误,可以指出,我不胜感激,让我们一起学习交流,如果文章可以给你一个帮助,可以给博主点一个小小的赞😘