- C语言中的数据类型大小和取值范围
- C语言中结构体和联合体的区别
- 大端字节和小端字节
一、C语言中的数据类型大小和取值范围
C语言中的数据类型通常有short、int、long、float、double、char六种类型。在32位的CPU中,各个数据类型所占的字节数分别为2,4,4,4,8,1。
1.C语言中常用各数据类型及其取值范围
有符号整数类型
类型名称 |
字节数 |
取值范围 |
Char |
2 |
-2^7 ~ 2^7-1 |
Short int |
4 |
-2^15 ~ 2^15-1 |
Int |
4 |
-2^31 ~ 2^31-1 |
Long int |
4 |
-2^31 ~ 2^31-1 |
Long long int |
8 |
-2^63 ~ 2^63-1 |
无符号整数类型
类型名称 |
字节数 |
取值范围 |
Unsigned char |
1 |
0 ~ 2^8 |
Unsigned short |
2 |
0 ~ 2^16 |
Unsigned int |
4 |
0 ~2^32 |
Unsigned long |
4 |
0 ~ 2^32 |
Unsigned long long |
8 |
0 ~ 2^64 |
二、C语言中结构体和联合体的区别
1、结构体struct
各成员各自拥有自己的内存,各自使用互不干涉,同时存在的,遵循内存对齐原则。一个struct变量的总长度等于所有成员的长度之和。
2、联合体union
各成员共用一块内存空间,并且同时只有一个成员可以得到这块内存的使用权(对该内存的读写),各变量共用一个内存首地址。因而,联合体比结构体更节约内存。一个union变量的总长度至少能容纳最大的成员变量,而且要满足是所有成员变量类型大小的整数倍。
代码1:struct字节对齐
在结构体U2中,a占4个字节,后面b和c共占3个字节,正好一个字节补齐;U3中b占1个字节,要和后面的int字节对齐就要补齐三个字节,后面的c也要补齐2个字节,所以U3共占12个字节。想要改变这种字节对齐方式,可以用:
#pragma pack (2) /*指定按2字节对齐*/
#pragma pack () /*取消指定对齐,恢复缺省对齐*/
#include<stdio.h>
struct u1
{
int a;
char b;
short c;
}U2;
struct u2
{
char b;
int a;
short c;
}U3;
int main(){
printf("%d\n",sizeof(U2));
printf("%d\n",sizeof(U3));
return 0;
}
//输出为
//8
//12
代码2:union大小计算
计算union的大小,必须要满足两个规则:(1)需要能够容纳最大的成员变量的大小;(2)满足是所有成员变量数据大小的整数倍
代码中U3至少容纳最大e[5]=20字节,同时变量类型最大值是整数倍,即使double(字节数是8)的整数倍,因而sizeof(U3)=24。
#include<stdio.h>
union u2 //u2联合体变量名
{
char a;
int b;
short c;
double d;
int e[5];
}U3;
//主函数
int main(){
printf("%d\n",sizeof(U3));//输出24
return 0;
}
三、大端字节和小端字节
计算机的数据以01构成的字节存储,这就涉及数据大小端的问题。计算机是大端数据模式还是小端数据模式对于普通的应用程序没有什么影响,但是在诸如网络编程、芯片寄存器操作的时候就有必要区分一下了,要不然会遇到程序的逻辑设计完全没问题,但得到的数据总是错误的尴尬。这里详细介绍一下这两种数据模式的差异,以及结合实际应用例子来检验我们主机的字节顺序模式。
字节顺序模式
计算机的字节顺序模式分为大端数据模式和小端数据模式,它们是根据数据在内存中的存储方式来区分的。小端字节顺序的数据存储模式是按内存增大的方向存储的,即低位在前高位在后;大端字节顺序的数据存储方向恰恰是相反的,即高位在前,低位在后。纯文字描述有点抽象,我们结合一个例子来说明一个16位的数据0xabcd在不同字节顺序的计算机内存中的存储情况。小端字节顺序中的数据存储是按照内存增长的方向存储的,0xabcd中的0xcd属于低位数据,故存在低八位,0xab属于高位数据,故存储高八位;大端字节顺序中的数据存储就反过来,高位数据0xab存储在低八位,低位数据0xcdb存储在高八位。小结:计算机的字节顺序模式就是数据在内存中存储方式的不同,小端数据模式与内存增长方向一致,大端数据模式与内存增长方向相反。
字节顺序应用
对字节顺序敏感的编程涉及的范围较多,这里以网络编程和芯片操作来说明大小端数据模式的转换问题。首先来说说网络编程,我们知道网络上的数据都是以大端数据模式进行交互的,而我们的主机大多数是以小端数据模式进行处理,它们如果不进行转换的话,势必会引起数据混乱。所以在网络编程中可以利用htons()、htonl()分别将16位、32位主机数据转换为网络字节序;ntohs()、ntohl()则分别将16位、32位网络字节序转换为主机数据。
另一个应用是芯片操作,这一块在嵌入式系统中应用比较多,一般在芯片的说明手册中都会详细说明芯片通信时使用的数据格式,如果遇到与主机的字节顺序不一样的,我们必须进行转换。假设芯片输出选用大端数据格式、主机是小端数据格式,当它们进行数据交互时,需要进行转换,比如主机想要发送一个16位的操作指令,我们可以通过移位、位与、位或等操作将数据进行字节顺序的转换。
检测主机字节顺序代码
了解大小端字节顺序后,我们如何知道我们的主机是用什么字节顺序呢。它的原理也很简单,利用共用体共用一段相同的内存,然后我们定义两个的变量(这里是short int与char),然后对长变量(short int 16位)进行初始化,接着按字节(char 8位)读取打印出来比较即可知道主机的字节顺序。
#include <stdio.h>
typedef union
{
unsigned short int value;
unsigned char byte[2];
}to;
int main(int argc.char *argv)
{
to typeorder;
typeorder.value = 0xabcd;
if(typeorder.byte[0] == 0xcd && typeorder.byte[1] == 0xab)
{
printf("low endian type order.byte[0] = 0x%x byte[1] = 0x%x\n",typeorder.byte[0],typeorer.byte[1]);
}
if(typeorder.byte[0] == 0xab && typeorder.byte[1] == 0xcd)
{
printf("hign endian type order.byte[0] = 0x%x byte[1] = 0x%x\n",typeorder.byte[0],typeorder.byte[1]);
}
return 0;
}