高位和低位的概念

1. "高位"和"低位"的概念

  在二进制(binary)和十六进制(hexadecimal)的表示中,"高位"和"低位"的概念是相对于数字的左侧和右侧而言的。通常,在数字的书写形式中,最左边的位是高位(Most Significant Bit, MSB),最右边的位是低位(Least Significant Bit, LSB)。

  • 二进制(binary):

    • 例如,数字 1011(在二进制中代表十进制的11)中,1(最左边)是高位,1(最右边)是低位。
  • 十六进制(hexadecimal):

    • 十六进制使用了0-9和A-F来表示数值,每个十六进制位对应4个二进制位(即一个nibble)。
    • 例如,在十六进制数 B2(在十六进制中代表十进制的178)中,B(最左边)是高位,2(最右边)是低位。

  在二进制和十六进制中,高位的值比低位的值具有更大的权重(或更高的重要性)。这是因为每个位都代表了一个2的幂(在二进制中)或16的幂(在十六进制中),而幂的指数随着位的位置向左移动而增加。因此,高位的变化会导致整个数值的更大变化。


2.小端字节序和大端字节序

  小端字节序(Little-Endian)和大端字节序(Big-Endian)是描述多字节数据在内存中存储顺序的两种不同方式。

  1. ** 大端字节序(Big-Endian)**:

    • 高位字节(Most Significant Byte, MSB)保存在内存的低地址处。
    • 低位字节(Least Significant Byte, LSB)保存在内存的高地址处。
    • 这种排列方式与人类习惯的数值书写顺序一致,例如十进制数“12345678”中,最高位数字“1”在最左边,最低位数字“8”在最右边。
    • 在大端字节序中,多字节数据在内存中的排列顺序与数值的书写顺序相同。
  2. 小端字节序(Little-Endian)

    • 高位字节(MSB)保存在内存的高地址处。
    • 低位字节(LSB)保存在内存的低地址处。
    • 这种排列方式与人类习惯的数值书写顺序相反,但更符合计算机内部处理数据的方式,因为CPU通常从内存的低地址开始读取数据。
    • 在小端字节序中,多字节数据在内存中的排列顺序与CPU读取数据的顺序一致。

示例
假设有一个16位的整数0x1234,其中0x12是高位字节,0x34是低位字节。

  • 在大端字节序中,这个整数在内存中的表示可能是这样的(假设从地址0x00开始):
    • 地址0x000x12
    • 地址0x010x34
  • 在小端字节序中,这个整数在内存中的表示可能是这样的(同样假设从地址0x00开始):
    • 地址0x000x34
    • 地址0x010x12

需要注意的是,不同的硬件平台和数据传输协议可能会使用不同的字节序。例如,x86和x86_64架构的CPU使用小端字节序,而一些网络和通信协议(如网络字节序)则使用大端字节序。因此,在跨平台编程和网络编程中,需要注意字节序的转换问题。


3.可以使用以下C或C++代码段来确定Linux系统的字节序

   在Linux系统中,CPU的字节序(是大端还是小端)通常是通过硬件确定的,并且可以通过编程来检测。大多数现代的个人计算机CPU使用小端字节序(Little-Endian),但服务器、嵌入式系统或某些特定的硬件可能使用大端字节序(Big-Endian)。

你可以使用以下C或C++代码段来确定Linux系统的字节序:

#include <stdio.h>

int check_endianness() {
    unsigned int x = 0x12345678;
    char *c = (char *)&x;
    if (*c == 0x78) {
        return 1; // Little-Endian
    } else {
        return 0; // Big-Endian or other (unusual)
    }
}

int main() {
    if (check_endianness()) {
        printf("The system is Little-Endian.\n");
    } else {
        printf("The system is Big-Endian or has an unusual endianness.\n");
    }
    return 0;
}

  在这段代码中,我们创建了一个无符号整数x,并给它赋了一个值0x12345678。然后,我们将这个整数的地址强制转换为字符指针c,并检查c所指向的字符值。如果这个字符值是0x78(即x在内存中的最低地址处的字节),那么系统就是小端字节序。否则,它可能是大端字节序或具有不寻常的字节序。

请注意,尽管上述代码在大多数情况下都能正确工作,但它假设char类型是有符号的,并且其大小为一个字节。这些假设在大多数现代系统上都是成立的,但在某些特殊的嵌入式系统或非常规的硬件上可能不成立。如果需要更健壮的代码,你可能需要考虑使用uint8_t类型(来自<stdint.h>)来确保字节大小始终为1,并且使用unsigned char来避免有符号扩展问题。

此外,有些系统提供了预定义的宏来检查字节序,例如__BYTE_ORDER__(在GCC和其他一些编译器中定义)。你可以检查这些宏来确定字节序,而无需编写自己的代码。例如:

#include <endian.h> // 对于某些系统,可能需要包含这个头文件
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    // Little-Endian
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
    // Big-Endian
#else
    // Other or unknown
#endif
 控制台输出如下
/home/linux/HQYJ/Level02_Embedded_applications/day20240517network_protocol/Endianness_of_Linux_systems
The system is Little-Endian.

Process finished with exit code 0

但是,请注意,并非所有的Linux系统都提供了__BYTE_ORDER__宏,因此在使用之前,你应该检查你的系统和编译器是否支持它。

  关于0x12345678在小端节序是先读78的解释:在小端字节序(Little-Endian)系统中,多字节数据的最低有效字节(Least Significant Byte, LSB)存储在最低的内存地址上,而最高有效字节(Most Significant Byte, MSB)则存储在较高的内存地址上。

对于32位整数0x12345678,在小端字节序系统中的内存布局会是这样的:

内存地址(从低到高):   |   78   |   56   |   34   |   12   |

所以当你从这个整数的最低内存地址开始读取时,首先读取到的是0x78,因为它是最低有效字节(LSB)。接着,随着地址的增加,你会依次读取到0x560x340x12

在编程和网络通信中,特别是当涉及到跨平台或跨网络的数据传输时,理解并处理字节序是非常重要的。如果发送方和接收方使用了不同的字节序,那么在接收方收到数据后,通常需要将其从网络字节序(大端字节序)转换为主机字节序(可能是小端或大端),或者从主机字节序转换为网络字节序。这可以通过调用如htonl(), ntohl(), htons(), ntohs()等函数(在POSIX兼容的系统中)来实现。

4.大部分Linux 是小端字节序(内存低位先读低位字节), 网络编程里是大端字节序

  在Linux系统中,大多数CPU架构(如x86, x86_64, ARM等)都使用小端字节序(Little-Endian)来存储多字节数据。但是,在网络编程中,为了保持跨平台的一致性,通常使用大端字节序(Big-Endian)来传输数据。

这是因为网络字节序(Network Byte Order)定义为大端字节序。当你使用套接字(sockets)进行网络编程时,你会遇到一些需要处理字节序的函数,如htonl(), ntohl(), htons(), ntohs()等。这些函数用于在主机字节序和网络字节序之间进行转换。

  • htonl():将32位主机字节序转换为网络字节序(大端)。
  • ntohl():将32位网络字节序转换为主机字节序。
  • htons():将16位主机字节序转换为网络字节序(大端)。
  • ntohs():将16位网络字节序转换为主机字节序。

在编写网络应用程序时,你需要确保在发送数据之前将数据从主机字节序转换为网络字节序,并在接收数据之后将数据从网络字节序转换回主机字节序。这是因为如果发送方和接收方的主机使用不同的字节序(虽然这在现代系统中不太可能,但理论上是有可能的),则直接传输原始字节可能会导致数据解释错误。

总之,Linux系统本身使用小端字节序,但在网络编程中,数据通常以大端字节序(网络字节序)进行传输。

  • 25
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C#,CRC(Cyclic Redundancy Check,循环冗余校验)是一种常见的数据完整性校验方法,用于检测数据传输过程的错误。当涉及到高位低位数组时,通常指的是将输入数据按照位操作进行分割,以便逐位计算CRC校验值。 以下是一个基本的C# CRC校验流程,假设我们有一个高位数组(高位字节)和低位数组(低位字节),使用XOR-GCC(或CRC-16)算法为例: 1. 初始化CRC寄存器:通常设置一个固定的初始值,例如0xFFFF(对于CRC-16)。 2. 将高位低位数组合并为单个数据流:根据需要,可能需要先按字节或位级合并这两个数组。 3. 逐位处理数据流:对于每个数据位,执行CRC计算,这包括XOR当前寄存器值和新输入的数据位,然后与一个生成多项式进行异或运算。 4. 高位数组处理:如果存在高位数组,可能需要对每个高位字节执行上述步骤,而忽略低位。 5. 结果处理:最后,计算完成后的CRC寄存器值即为校验结果,通常将其转换为16进制或二进制字符串形式显示。 以下是一个简化版的C#代码片段,假设`data`是高位低位数组的联合,`crcTable`是CRC-16的生成多项式: ```csharp byte[] data; byte[] crcTable = // ... 假设为XOR-GCC的生成多项式表 int crc = 0xFFFF; // 初始化CRC寄存器 for (int i = 0; i < data.Length; i++) { byte currentByte = data[i]; for (int j = 0; j < 8; j++) { if ((crc >> 15) == 1) // 如果最高位为1,则与当前字节的最低位进行异或 currentByte ^= 0x01; // CRC计算 crc = (crc << 1) ^ crcTable[(crc >> 14) & 0x0F]; // 位移并XOR } // 对高位字节进行相同的操作,如果适用 } // 将CRC转换为16进制或其他形式 string crcHex = BitConverter.ToString(BitConverter.GetBytes(crc)); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值