【C语言】大小端介绍以及判断大小端的两种方式

简介: 【C语言】大小端介绍以及判断大小端的两种方式

例子展示⁉️

我们把10这个整型存储在变量a中, 把-10存储在变量b中。

我们动手写一下就知道10存储在a中的补码

0000 0000 0000 0000 0000 0000 0000 1010 (原码反码补码)

转换为十六进制就是== 00 00 00 0a==

-10的原码是

1000 0000 0000 0000 0000 0000 0000 1010 (原码)

1111 1111 1111 1111 1111 1111 1111 0101 (反码)

1111 1111 1111 1111 1111 1111 1111 0110(补码)

转换为十六进制就是== FF FF FF F6==

调试起来看看内存

不应该是 00 00 00 0aFF FF FF F6吗?

下面我们来解释一下。

大端小端是什么呢?😶‍🌫️

大端(存储)模式 小端(存储)模式
将数据的高位存放到内存的低地址 ,数据的低位存放到内存的高地址 将数据的高位存放到内存的高地址,数据的低位存放到内存的低地址

也许这样说你可能不是很理解不要紧,下面我会画图讲解:

首先我们要知道一个叫字节序的概念:

0x22334455

这就是字节序,和高位低位的概概念

我们将0x22334455存放到a变量中,那么小端是怎么样呢?

那么大端就很明显了

这里补充一句:

对于一个字节的数据,它只有一个字节,没有字节序的概念。字节序是指多字节数据在内存中的存储顺序,而一个字节的数据只有一个字节,没有多个字节需要进行存储顺序的考虑。

为什么存在大小端呢?🚩

为什么会有大小端模式之分呢?

这是因为在计算机系统中,我们是以字节为单位的,

每个地址单元 都对应着一个字节,一个字节为8 bit。

但是在C语言中除了8 bit的char之外,

还有16 bit的short型,

32 bit的long型(要看具体的编译器),

另外,对于位数大于8位 的处理器,

例如16位或者32位的处理器,

由于寄存器宽度大于一个字节,

那么必然存在着一个如何将多个字节安排的问题。

因此就 导致了大端存储模式和小端存储模式。


那为什么我们在例子展示的时候,只是小端呢?
这样因为C语言并没有明确规定要怎么存储,大端小端是由编译器决定的。

判断大小端的两种方法

方法一

我们直接上代码:

int jugde(int a)
{
  char* str = (char *) & a;
  if (*str == 1)
  {
    return 1;
  }
  else
  {
    return 0;
  }
}
int main()
{
  int a = 0x1;
  int i = jugde(a);//返回1为小端,返回0为大端
  if (i)
  {
    printf("小端\n");
  }
  else
    printf("大端\n");
  return 0;
}

其实是比较简单的,

我们知道a = 0x00 00 00 01;

那么如果是小端存储 在内存中就是 01 00 00 00

我们将a 变量的值传到 judge 函数中,judge函数会创建一个新的变量a来接受0x 00 00 00 01,我们用一个char * 类型的指针指向a,或者说把a的地址放到str变量中,为什么是char * 类型呢?

我们知道指针类型决定了

  • 指针变量解引时能访问多少个字节,
  • 和指针±的步长为多大。

这里明显就是和访问字节相关,

char * 类型的指针能访问1个字节

也就说

  • 如果是小端 * str的值就是1,
  • 如果是小端 *str的值就是0,

是不是很巧妙。还有更巧妙的:

我们可以改进我们上面的这个代码:

int jugde(int a)
{
  char* str = (char *) & a;
  return (*str);
}
int main()
{
  int a = 0x1;
  int i = jugde(a);//返回1为小端,返回0为大端
  if (i)
  {
    printf("小端\n");
  }
  else
    printf("大端\n");
  return 0;
}

我们知道 * str的值无非两种,要么是0要么是1,那么为什么不直接返回 * str呢?

其实还能改进,

我们能不能不用指针呢?

当然可以!!

int jugde(int a)
{
  return *(char*)&a;
  }
int main()
{
  int a = 0x1;
  int i = jugde(a);//返回1为小端,返回0为大端
  if (i)
  {
    printf("小端\n");
  }
  else
    printf("大端\n");
  return 0;
}

我们先取地址a,然后强转为(char *)类型,这样我们解引用的范围就是一个字节了,然后就更上面的方法一样的,确实妙啊~~~。

第二种方法🦚

第二种方法运用了联合体!

int jugde()
{
  union test
  {
    int a;
    char b;
  }u;
  u.a = 1;
  return u.b;
}
int main()
{
  if (jugde() == 1)
  {
    printf("小端\n");
  }
  else
    printf("大端\n");
  return 0;
}

我们画图来简单看看:

这样我们就知道return u.b;到底是在干些什么。

总结🍊

我们在这篇博客中介绍了什么是大小端,为什么会有大小端,还有大小端的两种巧妙的判断方法,你全都get到了吗?

最后如果这篇博客有帮助到你,欢迎点赞关注加收藏

如果本文有任何错误或者有疑点欢迎在评论区评论


目录
相关文章
|
API iOS开发
彻底搞懂同步与异步,阻塞/非阻塞
彻底搞懂同步与异步,阻塞/非阻塞
3397 0
|
9月前
|
前端开发 JavaScript
什么是深拷贝;深拷贝和浅拷贝有什么区别;深拷贝和浅拷贝有哪些方法(详解)
浅拷贝适用于只复制对象的第一层属性,且这些属性不是引用类型。深拷贝适用于需要完全独立的副本,包括对象和数组的嵌套结构。选择哪种拷贝方式取决于你的具体需求和场景。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
存储 安全 API
基于FreeRTOS中的串口不定长接收(使用队列进行数据传输)
基于FreeRTOS中的串口不定长接收(使用队列进行数据传输)
1579 0
|
网络协议 算法 网络性能优化
|
存储 缓存 安全
【实战指南】轻松自研嵌入式日志框架,6大功能亮点一文读懂
本文介绍了如何自研一个嵌入式日志框架,涵盖了6大功能亮点:日志分级管理、异步处理与并发安全性、详尽上下文信息记录、滚动日志归档策略、高效资源利用和便捷API接口。设计上,通过日志过滤器、共享环形缓冲区和独立的日志管理进程实现日志管理。在并发环境下,使用信号量保证线程安全。日志文件按大小滚动并有序归档,同时考虑了资源效率。对外提供简洁的API接口,便于开发人员使用。文章还简述了实现细节,包括实时存储、日志滚动和共享内存管理。测试部分验证了日志回滚和实时打印功能的正确性。
630 4
|
传感器 芯片
嵌入式通信协议全解析:SPI、I²C、UART详解(附带面试题)
通信是指人与人或人与自然之间通过某种行为或媒介进行的信息交流与传递。从广义上来说,通信是指需要信息的双方或多方在不违背各自意愿的情况下采用任意方法、任意媒质,将信息从某方准确安全地传送到另方。在出现电波传递通信后,通信被单一解释为信息的传递,是指由一地向另一地进行信息的传输与交换,其目的是传输消息。通信方式包括利用“电”来传递消息的电信,这种通信具有迅速、准确、可靠等特点,且几乎不受时间、地点、空间、距离的限制,因而得到了飞速发展和广泛应用。
5030 0
|
Ubuntu 开发工具 git
ESP32-C3 VScode开发环境搭建(基于ESP-IDF—Windows和Ubuntu双环境)
对于ESP32-C3开发,自己对Arduino环境使用起来很是不习惯,既然乐鑫官方都出对应的环境,还是来试试官方环境
3757 0
ESP32-C3 VScode开发环境搭建(基于ESP-IDF—Windows和Ubuntu双环境)
|
存储 程序员 C语言
堆和栈之间有什么区别
【9月更文挑战第1天】堆和栈之间有什么区别
2840 0
|
存储 API 调度
FreeRTOS深入教程(任务创建的深入和任务调度机制分析)
FreeRTOS深入教程(任务创建的深入和任务调度机制分析)
2113 0
|
Unix Shell Linux
linux互斥锁(pthread_mutex)知识点总结
linux互斥锁(pthread_mutex)知识点总结