C语言大小端字节序存储模式深入解读

目录
  • 前言
  • 一、大小端介绍
    • 1. 大端字节序与小端字节序的概念
    • 2. 为什么会有大小端之分?
    • 3.一道和字节序相关的例题
      • 题干
      • 思路
  • 二、如何设计一个小程序判断当前机器的字节序
    • 百度2015年系统工程师笔试题
      • 题干
      • 解题

前言

本文以C语言实现,主要通过例题+说明的模式讲解存储模式:大小端字节序。

对于正整数而言,它的补码 = 原码 = 反码;

对于负整数而言,它的补码 = 原码按位取反(就是反码) + 1;

例如,当语句int a = 500被执行时,内存中会开辟 4字节(即32bit)的空间存储整数20的二进制补码(00000000 00000000 0000000111110100)。同时,我们也知道,内存中的每一个存储单元的大小为 1字节(8bit)。

那么此时问题来了:int a = 500所占的总空间是4字节,然而每一个内存单元只存的下1字节的数据,换句话说,每一个整型数据需要4个存储单元才能存的下——那么,这4个存储单元在内存中到底是如何分布的呢?

是像数组一样,用来存储数据的4个内存单元彼此之间连续开辟,还是物理空间上其实并不连续、只是解析数据时把4个单元中的数据“拼”到一起,还原出连续的整型数呢?

每一个字节的数据,如何“被安排”存储空间?

这个问题,本质上是数据在内存中的存储模式问题。这就关系到我们今天要介绍的重点:大端数据存储模式或小端数据存储模式(即大端字节序与小端字节序)。

我们打开编译器vs2019的内存监视,可以从监视窗口看到数值在内存中的存储情况(显示为16进制)。

注意:32位下,

20的16进制补码为:00 00 00 14

-10的十六进制补码为:ff ff ff f6

两个16进制位恰好是一个字节8bit。我们将视图调整为每行显示4个字节(即一个int,这样看得更清晰),于是可以发现,在内存中数据似乎是“倒着存”的。00 00 00 14在内存中的存储显示为了14 00 00 00.

事实上,这并不叫做“倒着存”,这正是我们上面提到过的:小端字节序的存储模式。在阅读完本文后,我们就能明白。

一、大小端介绍

当一个数值的大小超过 1字节 ,那么它要存到内存中,字节与字节之间就有存储顺序的问题。这个顺序称之为字节序。

以int类型为例。

理论上来说,即使存储一个int型数据的4个存储单元不连续,甚至天南海北,只要最终解析时能还原成一个正常的数即可。但是这么做属实没有必要:计算机中存储肯定是采用最便捷的存储方式,那就是连续存储,一个整型的4个字节空间挨在一块儿。

这时要考虑的问题便是,这四个挨在一块的存储空间,是由低地址向高地址存储,还是由高地址向低地址存储?

1. 大端字节序与小端字节序的概念

小端字节序:把一个数值的低位字节内容存放在低地址处;高位字节内容存放在高地址处。(低位存低地址,高位存高地址)。

大端字节序:把一个数值的低位字节内容存放在高地址处;高位字节内容存放在低地址处。(低位存高地址,高位存低地址)。

例如,要存储一个十六进制数 0x11223344。该数中右端是低数位,左端是高数位(类比十进制数,十进制数10里面0是个位更低,1是十位更高)。

小端存储情况如下:

小端存储模式示意

小端存储模式下,若取出该int型数据的首地址内容会发现,存的其实是0x44。

而大端存储情况如下:

大端存储模式示意

以上就是对大小端存储模式的理解。

至于实际中如何存储的,还取决于具体编译器的选择。现在大部分的编译器选择的是小端存储模式,也就是我们上面看到的“倒着存”。

这时再参照引言中的例子,应该能对这两种存储模式有一个较好的理解了。

2. 为什么会有大小端之分?

这是因为在计算机系统中,我们以字节为单位,每个地址单元都对应着一个字节,一个字节为8 bit 。但是在 C 语言中,除了 8 bit 的 char 之外,还有 16 bit 的 short 型,32 bit 的 long 型(要看具体的编译器);另外,对于位数大于 8 位的处理器,例如 16 位或者 32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。

例如,一个 16bit 的 short 型 x ,在内存中的地址为 0x0010 , x 的值为 0x1122 ,那么 0x11 为高字节,0x22 为低字节。

对于大端模式,就将 0x11 放在低地址中,即 0x0010 中, 0x22 放在高地址中,即 0x0011 中。 小端模式,刚好相反。我们常用的 X86 结构是小端模式,而 KEIL C51 则为大端模式。很多ARM , DSP 都为小端模式。有些 ARM 处理器还可以由硬件来选择是大端模式还是小端模式。

3.一道和字节序相关的例题

题干

在小端机器中,下面代码输出的结果是:

#include <stdio.h>
int main()
{
	int a = 0x11223344;
    char *pc = (char*)&a;
    *pc = 0;
    printf("%x\n", a);
    return 0;
}

思路

本题中的数值与我们上面讨论的数值一样,应该不难理解:

1. char*类型的指针变量pc指向的只能指向char类型的空间。如果是非char类型的空间,则必须将该空间的地址强转为char*类型。

2. char *pc = (char*)&a; pc实际指向的是整形变量a的空间,即指针pc里放的是0x00405090,指向的值即0x44。

3. *pc=0,关键一步:究竟是将哪个存储单元中的值置零了?由首个单元中存储的内容可知,将0x44位置中内容改为了0。修改完成之后,a中内容为:0x11223300 (数值书写肯定是高数位在左,低数位在右)

二、如何设计一个小程序判断当前机器的字节序

百度2015年系统工程师笔试题

题干

请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。( 10 分)

解题

概念部分同上,在此不再赘述。

代码部分:

1. 要检测某一机器是大端还是小端其实并不难,我们可以直接用int类型的1来检测。

2. 1在内存中的二进制补码为:00000000000000000000000000000001

也就是说,我们只需要把首个内存单元的值取出来看看是0还是1,就能判断它是大端还是小端。

因为如果是大端,则“高数位存在低地址”,我们取出最低地址的值,应当是最高数位上的数00000000;而若是小端,则“低数位存在低地址”,依然取出最低地址的值,应当是00000001

依照该思路,有以下代码:

#include <stdio.h>
int check_sys()
{
     int i = 1;
     return (*(char *)&i);
}
int main()
{
     int ret = check_sys();
     if(ret == 1)
     {
         printf("小端\n");
     }
     else
     {
         printf("大端\n");
     }
    return 0;
}

当然,也可以用共用体来实现检查,这是更为便捷的一种方式:

int check_sys()
{
     union
     {
         int i;
         char c;
     }un;
     un.i = 1;
    return un.c;
}

到此这篇关于C语言大小端字节序存储模式深入解读的文章就介绍到这了,更多相关C语言大小端字节序内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 用C语言程序判断大小端模式

    1.大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中:小端模式相反 2.为什么有大小端之分??? 因为在计算机系统中,存储是以字节为单位的,每个地址单元都对应着一个字节,一个字节=8bit.在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器).对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,如何安排多个字节的存储,这就有了大端存储模式和小端存储模式 3.各自的优势: 小端

  • C语言进阶几分钟带你理解大小端存储模式

    目录 正片开始 共用体原理 引申一下 字节顺序 大小端存储 共用体判断大小端 正片开始 C语言中数据类型的存储是较为严谨的,一块空间只能存储一种数据类型,要知道内存这个东西,在早期可是非常珍贵的. 尤其对于那些性能不好计算机更是如此,比如 Office1997,操作系统为Windows95 ,奔腾1的cpu,内存只有128M.就这么绿豆点大的存储空间,要想达到节约,利用最大化就必须在同一块空间中存入不同类型数据. 所以共用体的概念就随之产生,将几种不同类型的内容覆盖到同一内存单元,之前在我的一篇

  • C语言中大小端问题实例探索解决方法

    目录 一.什么是大小端 二.举个例子 三.大小端演示 四.解释"二"中举例的问题 五.怎么判断是大端还是小端 六.一个题目 一.什么是大小端 大端模式:就是高位字节数据存放在内存的低地址端,低位字节数据存放在内存的高地址端. 小端模式:就是低位字节数据存放在内存的低地址端,高位字节数据存放在内存的高地址端. [大端]和[小端]表示多字节值的哪一端存储在该值的起始地址处: 二.举个例子 #include<stdio.h> int main() { int a = 1; ret

  • C语言编程大小端问题示例详解教程

    目录 如何理解大小端 大小端的基本概念 大小端是如何影响数据的存取的 今天想给大家分享的,是数据存储中的大小端问题,今天的分享主要分为三个部分,分别是如何理解大小端,大小端的基本概念以及大小端是如何影响数据存取的. 如何理解大小端 首先先带大家了解一个权值的概念. 对于多位数,处在某一位上的"i"所表示的数值的大小,称为该位的位权,可以简单理解为权值. 权值大的即为高权值位,权值小的即为低权值位,例如 0x010001,从左边起第一个1表示的是1*2^7,第二个1表示的是1*2^0,事

  • 基于大端法、小端法以及网络字节序的深入理解

    关于字节序(大端法.小端法)的定义<UNXI网络编程>定义:术语"小端"和"大端"表示多字节值的哪一端(小端或大端)存储在该值的起始地址.小端存在起始地址,即是小端字节序:大端存在起始地址,即是大端字节序. 也可以说: 1.小端法(Little-Endian)就是低位字节排放在内存的低地址端即该值的起始地址,高位字节排放在内存的高地址端. 2.大端法(Big-Endian)就是高位字节排放在内存的低地址端即该值的起始地址,低位字节排放在内存的高地址端.举

  • C/C++字节序的深入理解

    目录 字节序 大端序 小端序 主机字节序和网络字节序 大端序和小端序的互转 字节序 最近在看 redis 的内存编码,里面涉及到字节序相关的内容.这里就当复习一下,做个简单的回顾. 数据存储在内存中,是以字节为单位的,如果是单字节数据(如char.unsigned char.int8)就不会有字节序的问题.但是多字节数据(如 int.float.double)就要考虑字节序的问题了.字节序共分为两种:大端序 和 小端序. 大端序 数据的高位字节存储在地址的低端:低位字节存储在地址的高端.如图所示

  • Go语言实现机器大小端判断代码分享

    golang语言如何判断机器的大小端? 如下代码供参考: 复制代码 代码如下: package main     import (       "fmt"      "unsafe"  )     const N int = int(unsafe.Sizeof(0))     func main() {       x := 0x1234       p := unsafe.Pointer(&x)       p2 := (*[N]byte)(p)     

  • 关于大小端、位域的一些概念详解

    大小端: 对于像C++中的char这样的数据类型,它本身就是占用一个字节的大小,不会产生什么问题.但是当数制类型为int,在32bit的系统中,它需要占用4个字节(32bit),这个时候就会产生这4个字节在寄存器中的存放顺序的问题.比如int maxHeight = 0x12345678,&maxHeight = 0x0042ffc4.具体的该怎么存放呢?这个时候就需要理解计算机的大小端的原理了. 大端:(Big-Endian)就是把数值的高位字节放在内存的低位地址上,把数值的地位字节放在内存的

  • C语言中数据是如何存储在内存中的

    目录 前言 ‍数据类型介绍 ‍整形数据在内存中存储 ‍浮点型数据在内存存储 前言 在计算机内存中,数据的存储方式都是以0和1的形式存储,也就是二进制的形式,数据是如何向内存写入的呢?整形数据以补码的形式存储,浮点型的存储规则较多,类似于科学计数法. ‍数据类型介绍 为什么需要有这些数据类型? 数据类型解决了数据存储的问题. ‍整形数据在内存中存储 整数中有三种二进制表示形式,分别是原码.反码.补码,正整数的原码 = 反码 = 补码,通常取最高位作为符号位. 原码:直接将正负整数按照二进制形式转换

  • C语言深入探索数据类型的存储

    目录 数据类型介绍 类型的基本归纳 整型家族 浮点数家族 构造类型 指针类型 空类型 整型在内存中的存储 原码,反码,补码 大小端 浮点数在内存中的存储 浮点数存储的规则 数据类型介绍 首先,对于我们C语言中的数据类型,大家应该都有一个清晰的认识吧!如果不记得也没有关系哦~ 在这里来跟着小刘同学回顾一下吧! 关于数据类型,我们在前面已经学习过了一些内置数据类型,以及它们所占的内存空间的大小,例如: char         //字符数据类型int          //整型short      

  • c++中的字节序与符号位的问题

    目录 c++的字节序与符号位 c++多字节值与字节序 多字节值与字节序 对于跨平台应用,字节序的两种处理方式 字节序的判断 整数字节序的转换 浮点数的字节序转换 c++的字节序与符号位 看这样一道题: #include <stdio.h> int main(void)  {     int w, h;     int i = 0xa1b2c3d4;     char *p = (char *)&i;     for (int j = 0; j < 4; j++)     {   

随机推荐