前言:
今天看官们对“c语言字节有什么用”都比较注意,小伙伴们都需要了解一些“c语言字节有什么用”的相关文章。那么小编在网上收集了一些有关“c语言字节有什么用””的相关文章,希望姐妹们能喜欢,同学们一起来了解一下吧!数据的大小端对不同平台数据传输具有重要意义,在具体使用时需要根据需要进行数据大小端转化,不然就会读出错误的数据。
为什么存在大小端呢?
这是因为在计算机系统中,我们是以字节为单位的,每个地址都对应着一个字节,一个字节为 8bit。但是在C语言中,其中 char 类型为1个字节,int型为4字节(通常看系统为多少位)。对于位数大于8位的处理器,例如16位或32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节存放的问题。因此就导致了大端存储和小端存储模式的问题.
1. 概念:
大端模式:把一个数据的低位字节序存放到高地址处,数据高位字节存放在低地址处;
小端模式:把一个数据的低位字节序存放到低地址处,数据高位字节存放在高地址处;
解释:数据的高低位是对于要存储的数据而言的,高低地址是针对内存来说的(内存以字节为单位)。
大小端其实是指针对数据的两种不同的存储方式,以下为两个例子来进一步说明:
---------------------------------------------------------------------------------------------------------
---举例1:
unsigned int value = 0x12345678,可以用unsigned char buf[4]来表示value: 1) 大端方式: 低地址存放高位,如下: buf[3] (0x78) -- 低位 buf[2] (0x56) buf[1] (0x34) buf[0] (0x12) -- 高位 2)小端方式: 低地址存放低位,如下: buf[3] (0x12) -- 高位 buf[2] (0x34) buf[1] (0x56) buf[0] (0x78) -- 低位
---------------------------------------------------------------------------------------------------------
---举例2:
定义一个数据 int a =1; a会存放在内存中;存储方式分为大端存储和小端存储。
int型数据占用四个字节,int a = 1;即a=0x00 00 00 01;
---便于记忆,可以总结口决为:大反小正;
2. 使用场景:
一般在不同主机端进行数据通信时会涉及到大小端数据格式的处理,如:网络通信,串口通信等;
网络上数据传输上往往采用大端模式进行数据传输;跨硬件平台进行数据传输,数据格式存在差异,存储字节的顺序可能不同;采用通讯协议每次传输数据的字节有一点限制等. 在通信中,大小端是十分重要的,也就是先发低字节还是先发高字节。通信前必须确认好大小端,否则不能正确解析传送过去的数据。
3. 判断大小端的几种方法:
1) 用指针的方式测试大小端:
short int x = 0x1122; char x0, x1; short int *p = &x; x0 = *( (char *)p + 0); //取低字节存储位置 x1 = *( (char *)p + 1); //取高字节存储位置 if(x0 == 0x22) { printf ("[%s]:little end mode!\n", __FUNCTION__); } else { printf ("[%s]:big end mode!\n", __FUNCTION__); }
解析说明:
a. 先定义一个short类型的变量(2个字节),能体现出高位字段和低位字段;
b. 再定义两个char类型字节,用于分开保存short类型的两个字节;
c. 定义一个short双字节类型的指针,并指向数据x;
d. 把short类型指针p强制转换成char *类型,按单个字节进行操作;
从0低位存储位置读取内容,分别放入x0和x1中;
e.按大小端定义进行比较;
如果x0(存储低端位置)的值为0x22(数据低端值 ),即为小端;
反之则为大端;
当然上述也可通过定义4个字节的int 类型进行测试,如:
int x=0x11223344; char x0, x1, x2, x3; int *p = &x; x0 = *( (char *)p + 0); x1 = *( (char *)p + 1); x2 = *( (char *)p + 2); x3 = *( (char *)p + 3);
大家可以自行测试。
2)使用联合结构体测试大小端:
typedef union { int a; char b; }test_union_t; eEnd_t endian_judge_method2 () { test_union_t u1; memset (&u1, 0, sizeof(test_union_t)); u1.a = 1; if (u1.b == 1) { printf ("[%s]:little end mode!\n", __FUNCTION__); } else { printf ("[%s]:big end mode!\n", __FUNCTION__); } }
解析说明:
原理:利用联合体的成员共享同一块内存,并且同时只能访问一个成员变量,成员变量的地址都是相同的。
a. 先对int型的变量a赋值。假设这是32位的系统,int型占4个字节,对int型的变量赋值1;应该是0x00000001;
b. 这个1可能被放在高地址,也可能被放在低地址,由此可以判断大小端。
c. 这里有个隐含条件,不管是int型变量还是char型变量,起始地址都是一样的,起始地址都是四个字节里最低的那个字节的地址。
d. 当对a赋值后,四个字节里存放的数据情况:
大端则存储的4个字节:
低地址----->高地址
0X0 ,0X0 ,0X0 ,0X1
小端则存储的4个字节:
低地址----->高地址
0X1 ,0X0 ,0X0 ,0X0
e. 最后可通过直接获取char类型的变量b的值可知具体的大小端情况;
3) 完整代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef enum { ENDIAN_LITTLE, ENDIAN_BIG } eEnd_t; /*方法1 :使用指针方法来判断大小端方式*/ eEnd_t endian_judge_method1() { short int x = 0x1122; char x0, x1; short int *p = &x; x0 = *( (char *)p + 0); x1 = *( (char *)p + 1); if(x0 == 0x22) { printf ("[%s]:little end mode!\n", __FUNCTION__); return ENDIAN_LITTLE; //little end; } else { printf ("[%s]:big end mode!\n", __FUNCTION__); return ENDIAN_BIG; //big end; } } /*方法2 :使用联合方法来判断大小端方式*/ typedef union { int a; char b; }test_union_t; eEnd_t endian_judge_method2 () { test_union_t u1; memset (&u1, 0, sizeof(test_union_t)); u1.a = 1; if (u1.b == 1) { printf ("[%s]:little end mode!\n", __FUNCTION__); return ENDIAN_LITTLE; } else { printf ("[%s]:big end mode!\n", __FUNCTION__); return ENDIAN_BIG; } } int main (int argc, char **argv) { endian_judge_method1 (); endian_judge_method2 (); return 0; }
==》运行结果:
[endian_judge_method1]:little end mode! [endian_judge_method2]:little end mode!4. 大小端转换方法:
原理:就是从低到高顺序重新排列,交换位置;
1)简单大小端转换的宏
/* 32位数据小端模式 */ #define uint32_data(x) //定义32位数据,这里x为用户自己定义的需要转化的数据 (uint32_t)((((uint32_t)(x) & 0xff000000) >> 24) |\ //这里是ff000000不是ffff0000,按照每两个字节进行的转化 (((uint32_t)(x) & 0xff000000) >> 8) |\ //数据右移8位 (((uint32_t)(x) & 0x0000ffff) << 8) |\ //数据左移8位 (((uint32_t)(x) & 0x000000ff) << 24)\ ) /* 16位数据小端模式 */ #define uint16_data(x) //定义16位数据,这里x为用户自己定义的需要转化的数据 (uint16_t)((((uint16_t)(x) & 0x00ff) << 8) |\ ((((uint16_t)(x) & 0xff00) >> 8) \ )
2)网络socket开发接口中使用到的字节顺序转换函数:
#include <arpa/inet.h> /***************************************** *** 将 32位主机字节序数据转换成网络字节序数据 ***(h:host, n:net,l:long) *****************************************/ uint32_t htonl(uint32_t hostint32); /***************************************** *** 将16位主机字节序数据转换成网络字节序数据 *****************************************/ uint16_t htons(uint16_t hostint16); /***************************************** ***将 32 位网络字节序数据转换成主机字节序数据 *****************************************/ uint32_t ntohl(uint32_t netint32); /***************************************** ***将 16 位网络字节序数据转换成主机字节序数据 *****************************************/ uint16_t ntohs(uint16_t netint16);
补充说明:
a. 网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释,
网络字节顺序采用big-endian排序方式。
b. htons是将整型变量从主机字节顺序转变成网络字节顺序,即大端顺序(big-endian)。
c. htonl,其实是host to network, l是返回类型是long. 将主机数转换成无符号长整型的网络字节顺序。
本函数将一个32位数从主机字节顺序转换成网络字节顺序。
标签: #c语言字节有什么用 #long在c语言中占几个字节 #c语言类型字节大小 #c语言中一个字节是多大 #c语言一个字节等于几个串长