一文讲清楚大小端模式,字节对齐与左右对齐

11 篇文章 0 订阅
4 篇文章 0 订阅

目录

大小端

一、什么是大小端模式

二、为什么会有大小端之分

三、怎样判断大小端

1、通过强制类型转换截断

2、利用联合体共享内存的特性,截取低地址部分

 字节对齐

1、什么是内存对齐?

2、为什么要内存对齐?

3、内存对齐规则?

4、C++如何进行内存对齐?

ADC读取左对齐与右对齐

1.右对齐数据读取问题

2.左对齐数据读取问题


大小端

一、什么是大小端模式

一个32位的2进制在内存中存储时有两种发布方式:

高字节 对应 高地址 --------------> 小端模式

高字节 对应 低地址 --------------> 大端模式

示意图如下:

二、为什么会有大小端之分

1. 一开始是由于不同架构的CPU处理多个字节数据的顺序不一样,比如x86的是小段模式,KEIL C51是大端模式。但是后来互联网流行,TCP/IP协议规定为大端模式,为了跨平台通信,还专门出了网络字节序和主机字节序之间的转换接口(ntohs、htons、ntohl、htonl)

2. 大小端模式各有优势:小端模式强制转换类型时不需要调整字节内容,直接截取低字节即可;大端模式由于符号位为第一个字节,很方便判断正负。

三、怎样判断大小端

基本思想室根据数据截断来判断是大端还是小端

1、通过强制类型转换截断

 BOOL IsBigEndian()
 {
 	short a = 0x1234;
 	char b = *(char*)&a;
 	if(0x12 == b)
 	{
 	    return TRUE;
 	}
 	
	return FALSE;
  }

 

2、利用联合体共享内存的特性,截取低地址部分

  BOOL IsBigEndian()
  {
 	union NUM
 	{
 	    short  a;
 	    char b;
 	}num;
 	
 	num.a = 0x1234;
 	
 	if(0x12 == num.b)
 	{
 	    return TRUE;
 	}
 	
 	return FALSE;
  }

 字节对齐

1、什么是内存对齐?

理论上计算机对于任何变量的访问都可以从任意位置开始,然而实际上系统会对这些变量的存放地址有限制,通常将变量首地址设为某个数N的倍数,这就是内存对齐。

2、为什么要内存对齐?

  • 硬件平台限制,内存以字节为单位,不同硬件平台不一定支持任何内存地址的存取,一般可能以双字节、4字节等为单位存取内存,为了保证处理器正确存取数据,需要进行内存对齐。
  • 提高CPU内存访问速度,一般处理器的内存存取粒度都是N的整数倍,假如访问N大小的数据,没有进行内存对齐,有可能就需要两次访问才可以读取出数据,而进行内存对齐可以一次性把数据全部读取出来,提高效率。

3、内存对齐规则?

  • 数据成员对齐规则:struct或者union的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员都按照#pragma pack数值和这个数据成员自身大小中更小的那个进行对齐。
  • 整体对齐规则:struct或者union的首地址按照内部最大数据成员的大小和#pragma pack数值较小的那个N进行对齐,并且结构体的总大小为N的整数倍,如有必要编译器也会在最后一个成员后面填充一些字节用于对齐。

4、C++如何进行内存对齐?

class A
{
    int a;
    char d;
};

// 创建给定类型对象大小满足对齐要求的未初始化内存块,在一个内存对齐的缓冲区上创建对象
// C++11后可以这样操作
void align_cpp11_after()
{
    static std::aligned_storage<sizeof(A),
                                alignof(A)>::type data;
    A *attr = new (&data) A;
}

// C++11之前
void align_cpp11_before()
{
    static char data[sizeof(void *) + sizeof(A)];
    const uintptr_t kAlign = sizeof(void *) - 1;
    char *align_ptr =
        reinterpret_cast<char *>(reinterpret_cast<uintptr_t>(data + kAlign) & ~kAlign);
    A *attr = new (align_ptr) A;
}

 

ADC读取左对齐与右对齐

1.右对齐数据读取问题

其转换结果可以读取的语句为:     resualt=int(ADCH)*256+ADCL;
右对齐的时候,10位ADC的结果表示方式为ADCH:ADCL,ADCH是10bit结果的高2位,ADCL是10bit结果的低8位,如果要将ADC的结果存储到一个int型的变量中,那就需要先将ADCH的结果左移8位,再和ADCL的相加,其原理如下图所示:

左移8位等价于乘以256. 也可以将ADC转化为以256为权的数值表示,即:
resualt =  int(ADCH)*256^1+ADCL*256^0;   这样就可以清楚地理解这个数字的含义了。

2.左对齐数据读取问题

同理,左对齐如下表示:
Kotlin 协程是一种轻量级的线程处理方式,它可以让开发者更加方便地处理异步任务。本文将讲解 Kotlin 协程的使用方法。 ## 协程的概念 协程是一种轻量级的线程处理方式,它可以在一个线程中处理多个任务。在协程中,任务可以在任何时间点被挂起并在稍后的时间点恢复执行。与线程不同,协程是由程序员控制的,因此可以更加高效地使用系统资源。 ## 协程的优点 1. 更加高效地使用系统资源:协程可以在一个线程中处理多个任务,因此可以更加高效地使用系统资源。 2. 更加方便的异步处理:协程可以让开发者更加方便地处理异步任务。在协程中,异步任务可以像同步任务一样编写,这样可以让代码更加简洁易懂。 3. 更加灵活的控制流程:协程可以让程序员更加灵活地控制流程。在协程中,任务可以在任何时间点被挂起并在稍后的时间点恢复执行,这样可以让程序员更加方便地控制任务的执行顺序。 ## 协程的使用方法 ### 1. 创建协程 在 Kotlin 中,可以使用 `launch` 函数来创建一个协程。下面是一个简单的示例: ```kotlin import kotlinx.coroutines.* fun main() { GlobalScope.launch { println("Hello, World!") } } ``` 在上面的示例中,`GlobalScope` 表示全局协程作用域,`launch` 函数表示创建一个协程。在协程中,我们可以编写需要执行的代码,这里我们只是打印了一句话。 ### 2. 挂起协程 在协程中,可以使用 `delay` 函数来挂起协程。下面是一个简单的示例: ```kotlin import kotlinx.coroutines.* fun main() { GlobalScope.launch { println("Start") delay(1000) println("End") } } ``` 在上面的示例中,我们使用 `delay` 函数来挂起协程,让程序等待一秒钟后再执行后面的代码。 ### 3. 异步处理 在协程中,可以使用 `async` 函数来处理异步任务。下面是一个简单的示例: ```kotlin import kotlinx.coroutines.* fun main() { val deferred = GlobalScope.async { delay(1000) "Hello, World!" } println(deferred.await()) } ``` 在上面的示例中,我们使用 `async` 函数来处理异步任务。在异步任务中,我们使用 `delay` 函数来模拟一个耗时的操作。在主线程中,我们使用 `await` 函数来等待异步任务的执行结果,并打印出来。 ## 总结 协程是一种轻量级的线程处理方式,它可以让开发者更加方便地处理异步任务。在协程中,任务可以在任何时间点被挂起并在稍后的时间点恢复执行。协程可以更加高效地使用系统资源,更加方便地异步处理,更加灵活地控制流程。在 Kotlin 中,可以使用 `launch` 函数来创建一个协程,使用 `delay` 函数来挂起协程,使用 `async` 函数来处理异步任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值