
C语言中关于数据类型占用
bit、byte、KB、B、字节、位、字符之间关系详解
bit就是位,也叫比特位,是计算机表示数据最小的单位
byte就是字节 1byte=8bit
1byte就是1B
一个字符=2字节
1KB=1024B
字节就是Byte,也是B
位就是bit也是b
转换关系如下:1KB=1024B 1B=8b
字符与字节
ASCII码:一个英文字母(不分大小写)占一个字节的空间。一个二进制数字序列,在计算机中作为一个数字单元,一般为8位二进制数(二级制数即计算机中的0或1)。换算为十进制 ,最小值-128,最大值127。如一个ASCII码就是一个字节
UTF-8编码:一个英文字符等于一个字节,一个中文(含繁体)等于三个字节。中文标点占三个字节,英文标点占一个字节
Unicode编码:一个英文字符等于两个字节,一个中文(含繁体)等于两个字节。中文标点占两个字节,英文标点占两个字节
B与bit
数据存储是以字节(Byte)为单位,数据传输大多是以位(bit,又名“比特”)为单位,一个位就代表一个0或1(即二进制),每8个位(bit,简写为b)组成一个字节(Byte,简写为B),是最小一级的信息单位。
B与iB
1KiB(Kibibyte)=1024byte
1KB(Kilobyte)=1000byte
1MiB(Mebibyte)=1048576byte
1MB(Megabyte)=1000000byte
硬盘生产商是以GB(十进制,即10的3次方=1000,如1MB=1000KB)计算的,而电脑(操作系统)是以GiB(2进制,即2的10次方, 如1MiB=1024KiB)计算的,但是国内用户一般理解为1MiB=1M=1024 KB, 所以为了便于中文化的理解,翻译MiB为MB也是可以的。同样根据硬盘厂商与用户对于1MB大小的不同理解,所以好多160G的硬盘实际容量按计算机实际的1MiB=1024KB算都不到160G,这也可以解释为什么新买的硬盘“缺斤短两”并没有它所标示的那么大。
C语言各种基本数据类型字节大小和取值范围
- C语言中各种数据类型的字节占用和取值范围主要与所用的编译器(16位编译器,32位编译器等)和数据类型的定义规则有关,当然也会受到目标平台的字长(计算机进行整数运算所能处理的二进制数据的位数)的影响
- 如何知道当前编译环境下c语言中的基本数据类型的占用字节大小呢? 举例:sizeof(int)即可获取int类型的字节占用大小
- 如何知道当前编译环境下c语言中的基本数据的取值范围呢? 基于极限值符号(极限值符号在limits.h头文件中有定义)获得,CHAR_MIN, CHAR_MAX代表char的min和max值
基本数据类型
1.1.有符号整数类型(signed)
类型名称 | 占用字节数(bytes) | 取值范围 |
---|---|---|
signed char | 1 | -2^7(-128) ~ 2^7-1(127) |
short int 或 short | 2 | -2^15(-32 768) ~ 2^15-1(32 767) |
int | 4 | -2^31(-2 147 483 648) ~ 2^31-1(2 147 483 647) |
long int 或 long | 4 | -2^31(-2 147 483 648) ~ 2^31-1(2 147 483 647) |
long long int 或 long long | 8 | -2^63(-9.2233720368548e+18) ~ 2^63-1(9.2233720368548e+18) |
1.2.无符号整数类型(unsigned)
类型名称 | 占用字节数(bytes) | 取值范围 |
---|---|---|
unsigned char | 1 | 0 ~ 2^8-1(255) |
unsigned short int 或 unsigned short | 2 | 0 ~ 2^16-1(65 535) |
unsigned int | 4 | 0 ~ 2^32-1(4 294 967 295) |
unsigned long int 或 unsigned long | 4 | 0 ~ 2^32-1(4 294 967 295) |
unsigned long long int 或 unsigned long long | 8 | 0 ~ 2^64-1(1.844674407371e+19) |
2.1.浮点类型
类型名称 | 占用字节数(bytes) | 取值范围 |
---|---|---|
float | 4 | -/+3.4e38(精确到6位小数) |
double | 8 | -/+1.7e308(精确到15位小数) |
long double | 12 | -/+1.19e4932(精确到18位小数) |
3.1.表示有符号整数类型的极限值符号
类型名称 | 下限(min) | 上限(max) |
---|---|---|
char | CHAR_MIN | CHAR_MAX |
short | SHRT_MIN | SHRT_MAX |
int | INT_MIN | INT_MAX |
long | LONG_MIN | LONG_MAX |
long long | LLONG_MIN | LLONG_MAX |
3.2.表示无符号整数类型的极限值符号
类型名称 | 下限(min) | 上限(max) |
---|---|---|
unsigned char | 0 | UCHAR_MAX |
unsigned short | 0 | USHRT_MAX |
unsigned int | 0 | UINT_MAX |
unsigned long | 0 | ULONG_MAX |
unsigned long long | 0 | ULLONG_MAX |
3.3.表示浮点类型的极限值符号
类型名称 | 下限(min) | 上限(max) |
---|---|---|
float | FLT_MIN | FLT_MAX |
double | DBL_MIN | DBL_MAX |
long double | LDBL_MIN | LDBL_MAX |
1byte(字节)=8bit(比特)
则int类型的占用4bytes(字节)=32bits(比特)
00000000 00000000 00000000 00000000
第一bit 0用于表示符号(正负),剩下的31bit用于决定数字,int类型的取值范围就为 -2^31(-2 147 483 648) ~ 2^31-1(2 147 483 647)
那么为什么后面是2 147 483 647而不是2 147 483 648,因为还有一个0,-2 147 483 648 ~ 0 ~ 2 147 483 647
uint8_t / uint16_t / uint32_t /uint64_t的来源和作用
C语言数据类型及typedef下的uint8_t / uint32_t_typedef uint8-CSDN博客
来源
在基于C语言的代码中总能看到uint8_t / uint16_t / uint32_t /uint64_t的身影。如:uint32_t a = 300;
但它似乎又不属于C语言中的6种基本数据类型(short、int、long、char、float、double),那么它是一种新的数据类型?
*_t表示该标识由typedef定义得到,是结构的一种标注。C语言代码中的uint8_t / uint16_t / uint32_t /uint64_t都不是新的数据类型,而是通过typedef给数据类型起得新名字,如:
1 | typedef signed char int8_t; |
作用
1.增加代码的可读性
uint8_t,uint32_t能更明显的显示所占字节数。
uint8_t表示占1个字节(1 字节=8 bit);
uint32_t表示占4个字节(4 字节=32 bit)。
2.增加代码的可维护性
在涉及到跨平台时,不同的平台会有不同的字长,所以利用预编译和typedef可以方便的维护代码。
注:uint8_t实际上就是一个char,所以输出 uint8_t类型的变量实际上输出对应的字符,而不是数值,如:
1 | uint8_t num=67; |
总结
uint8_t / uint16_t / uint32_t /uint64_t不是新的数据类型,而是通过typedef给数据类型起的新名字
其他数据类型
指针变量
一个指针占几个字节?原理是什么呢?_指针大小几个字节-CSDN博客
指针的本质是一个整数,它存储的是内存地址。通过指针能找到或访问到内存中所有的地方。
某计算机的地址总线是32位,那么其一次可以处理的信息是32条,每一条地址总线有0或1两种可能,那么32根地址总线一共有2^32^种可能,也就是其描述的地址空间为0x0000 0000 ~ 2^32^-1。
我们一般需要32个0或1的组合就可以找到内存中所有的地址,而32个0或1的组合,就是32个位,也就是4个字节的大小,因此,我们只需要4个字节就可以找到所有的数据。
所以,在32位的计算机中,指针占4个字节。
同理,在64位的计算机中,指针占8个字节。
同时也可以看出,由于地址总线为32,那么每次寻址的空间为:
0000 0000 0000 0000 0000 0000 0000 0000 ~ 2^32^-1,那么CPU的最大内存为
2^32^ = 2^22^K = 2^12^M = 2^2^G = 4G
而单位是内存最小操作单位Byte,因此,加上单位Byte后:
2^32^Byte = 2^22^KB = 2^12^MB = 2^2^GB = 4GB
也就是,32位的电脑,CPU的最大内存为4GB
而64位,最大内存是2^64^Byte = 2^32^ * 2^32^Byte = 2^32^ * 4GB 约等于 17179869184GB。
字节(Byte)是计算机中表示信息含义的最小单位。一个字节由8个位组成,可以表示256种不同的值(2^8)。字节之所以成为内存的最小单位,主要是因为它能够直接表示一个ASCII字符,方便处理文本数据。此外,字节与计算机硬件的设计紧密相关,大多数现代计算机以字节为基础进行内存寻址和数据操作。
即:在32位系统中,地址总线宽度为32位,所以可以寻址的最大内存空间是4GB(2的32次方),因此一个指针(即一个地址)需要4字节(32位)的空间来存储。类似地,在64位系统中,地址总线宽度为64位,所以一个指针需要8字节的空间来存储。
常见硬件架构下数据总线和地址总线宽度的示例:
CPU架构 | 数据总线宽度 | 地址总线宽度 | 最大内存寻址 | 指针大小 |
---|---|---|---|---|
8位 | 8位 | 16位 | 64KB | 1字节 |
16位 | 16位 | 20位 | 1MB | 2字节 |
32位 | 32位 | 32 位 | 4 GB | 4字节 |
64位 | 64位 | 64位 | 16 EB | 8字节 |
枚举类型
C语言enum占几个字节?它在底层是哪种整数类型? - C语言中文网
在C语言中,enum(枚举类型)是一种用户自定义的数据类型,它允许程序员为一组相关的常量赋予有意义的名称。enum 的本质是一种整形常量,它的大小和底层表示方式可能会因编译器和目标平台的不同而有所差异。
enum 的内存占用通常取决于编译器如何选择存储枚举值,大多数现代编译器会选择能够容纳枚举中最大值的最小整数类型。这意味着 enum 的大小可能是 1、2、4 或 8 字节,具体取决于枚举值的范围和编译器的实现。
为了更好地理解这一点,我们来看一个具体的例子:
1 | enum Color { |
在大多数 32 位或 64 位系统上,这段代码的输出可能是:
1 | Size of enum Color: 4 bytes |
在这个例子中,enum Color 只包含小的正整数值(0、1、2),而 enum LargeEnum 包含一个较大的值(1000000)。尽管如此,它们在大多数系统上都占用 4 字节,因为编译器通常会选择 int 作为默认的底层类型。
然而,需要注意的是,C 标准并没有严格规定 enum 的大小,一些编译器可能会根据枚举值的范围选择更小的类型。例如,如果所有枚举值都小于 256,编译器可能会使用 unsigned char 作为底层类型,从而使 enum 只占用 1 字节。但一般来说在C 语言中,枚举类型是被当做 int 或者 unsigned int 类型来处理的。
关于 enum 的底层整数类型,C 标准规定它必须是某种带符号或无符号的整数类型。在大多数实现中,默认情况下会使用 int 类型。但是,如果枚举值超出了 int 的范围,编译器可能会选择更大的类型,如 long 或 long long。
为了确保跨平台的一致性,C99 标准引入了固定大小的整数类型,如 int32_t 或 uint32_t。一些编译器可能会使用这些类型作为 enum 的底层表示,以提供更可预测的行为。
值得一提的是,C++ 对 enum 的处理方式略有不同。C++11 引入了“枚举类”(enum class),它允许程序员明确指定底层类型:
1 | enum class Color : uint8_t { |
在这个 C++ 的例子中,我们明确指定 Color 枚举使用 uint8_t 作为底层类型,因此它将始终占用 1 字节。
对于C语言开发者来说,了解 enum 的内存占用和底层表示很重要,特别是在进行底层系统编程、嵌入式开发或需要精确控制内存布局的场景中。如果你需要确保 enum 使用特定大小的整数类型,可以考虑使用类型定义(typedef)结合固定大小的整数类型来模拟枚举:
1 |
|
C语言数据类型及typedef下的uint8_t / uint32_t_typedef uint8-CSDN博客
ColorType被显式定义为 uint8_t(1字节无符号整数),确保固定内存占用
这种方法可以让你更精确地控制枚举值的大小和类型,但代价是失去了一些 enum 提供的类型安全性和可读性。
总之,enum 在C语言中的大小和底层类型可能会因编译器和平台而异。大多数情况下,它会被实现为 int 类型并占用 4 字节,但这并不是绝对的。在编写跨平台或对内存布局敏感的代码时,建议使用 sizeof 运算符来确定实际大小,并考虑使用固定大小的整数类型来获得更可预测的行为。
结构体类型
[揭秘C语言struct大小之谜:深度解析结构体内存占用与布局优化 - 云原生实践](https://www.oryoy.com/news/jie-mi-c-yu-yan-struct-da-xiao-zhi-mi-shen-du-jie-xi-jie-gou-ti-nei-cun-zhan-yong-yu-bu-ju-you-hua.html#:~:text=本文将深入解析C语言中结构体的内存占用与布局优化,帮助开发者更好地理解和利用结构体。 结构体的内存占用首先取决于其成员数据类型的大小。 在C语言中,每个数据类型都有其固定的字节大小。 例如,一个 int,类型通常占用4字节,一个 float 类型占用4字节,一个 char 类型占用1字节。 在C语言中,结构体成员的内存占用还会受到成员对齐的影响。)
前言
在C语言编程中,结构体(struct)是一种非常重要的数据类型,它允许我们将多个不同类型的数据组合成一个单一的数据结构。然而,结构体的大小并不是固定的,其大小受多种因素影响,如数据类型的大小、成员的排列顺序等。本文将深入解析C语言中结构体的内存占用与布局优化,帮助开发者更好地理解和利用结构体。
数据类型大小
结构体的内存占用首先取决于其成员数据类型的大小。在C语言中,每个数据类型都有其固定的字节大小。例如,一个int
类型通常占用4字节,一个float
类型占用4字节,一个char
类型占用1字节。
成员对齐
在C语言中,结构体成员的内存占用还会受到成员对齐的影响。编译器会根据编译器选项和目标平台的硬件要求,对结构体成员进行对齐。常见的对齐方式包括:
- 字节对齐:成员的起始地址是其类型大小的整数倍。
- 半字节对齐:成员的起始地址是其类型大小的一半的整数倍。
- 双字节对齐:成员的起始地址是其类型大小的两倍的整数倍。
例如,以下结构体:
1 | struct Example { |
如果使用字节对齐,那么float
类型的b
成员将会占用4字节,起始地址为4的整数倍。由于int
类型的a
成员占用4字节,因此整个结构体的内存占用为8字节。
a | a | a | a |
---|---|---|---|
b | b | b | b |
空 | 空 | 空 | 空 |
例子分析
1 |
|
输出结果为:
1 | Size of struct Example: 8 bytes |
这符合我们的分析,结构体Example
的大小为8字节。
下面再来举一个例子,大家觉得下面这个结构体变量data占多少字节?
1 | struct STUDENT |
首先最长的数据类型占 4 字节,所以是以 4 对齐。然后 a 占 1 字节,b 接在 a 后面占 1 字节,c 接在 b 后面占 1 字节,d 接在 c 后面占 1 字节,此时满 4 字节了,e 再来就要另起一行。f 想紧接着 e 后面分配,但 e 后面还剩 3 字节,小于 int 类型的 4 字节,所以 f 另起一行。即该结构体变量分配内存时如下:
a | b | c | d |
---|---|---|---|
e | 空 | 空 | 空 |
f | f | f | f |
即总共占 12 字节。
结构体布局优化
顺序优化
为了减少结构体的内存占用,我们可以调整成员的顺序。将较小的成员放在前面,可以减少对齐开销,从而减小整个结构体的内存占用。
联合体使用
在某些情况下,可以使用联合体(union)来减少内存占用。联合体允许存储多个数据类型在同一个内存地址,但任何时刻只能存储一个类型的数据。
例子分析
1 |
|
输出结果为:
1 | Size of struct Example: 8 bytes |
这表明通过调整成员顺序和使用联合体,我们可以有效地减小结构体的内存占用。
总结
本文深入解析了C语言中结构体的内存占用与布局优化。通过了解数据类型大小、成员对齐以及顺序优化等概念,我们可以更好地控制结构体的内存占用,从而提高程序的性能和效率。在实际开发过程中,开发者应结合具体需求,合理运用结构体,以达到最佳效果。