字节对齐和字节序

2023-11-18

1、字节对齐

1、什么是字节对齐

内存空间是按字节划分,理论上可以从任意起始地址访问任意类型的变量。但实际上在访问特定类型变量是经常在特定的内存地址访问,这就需要各种数据类型按照一定的规则进行排列,而不是一个接一个紧接着排放。简单的讲就是数据存放的地址要满足一定的规则。

例如32位的计算机处理器通过总线访问内存数据。每个总线周期从偶地址开始访问32位数据,如果一个32位的数据没有存放在4字节整除的内存地址处,那么处理器就需要两个总线周期对其进行访问,显然会降低访问效率。因此,通过合理的内存对齐可以提高访问效率。为使得cpu对数据能够进行快速访问,数据的起始地址应该遵循对齐规则。比如,4字节数据的起始地址应该能被4整除。字节对齐需要考虑处理器的类型和编译器的类型。

2、字节对齐的作用:

(1)合理的内存对齐可以提高cpu访问效率

(2)~可以节省存储空间

(3)可以减少cpu访问内存的出错概率

字节对齐最主要反映在数据结构对齐,字节对齐原则如下:

1、基本数据类型自身对齐值:按照自身数据长度作为对齐值

2、结构体或类的自身对齐值:其成员中自身对齐值最大的最大值

3、指定对齐值:#pragma pack(value)指定对齐值为value

4、数据成员、结构体和类的有效对齐值:自身对齐值和有效对齐值中较小者

#include <stdio.h>
#include <stdlib.h>

#define debug_printf(value) printf(#value " ---==> %d\n", value)
#define debug_struct_member_offset(struct, member) (((char *)(&(((struct *)0)->member))) - ((char *)0))
typedef struct data_type1{
    char a[2];
    short b;
    int c;
} Data_type1;
typedef struct data_type2{
    short a;
    int b;  
    char c[2];
} Data_type2;
int main(int argc, char** argv){
    int a,b,c;
    a = debug_struct_member_offset(Data_type1,a);
    b = debug_struct_member_offset(Data_type1,b);
    c = debug_struct_member_offset(Data_type1,c);
    debug_printf(sizeof(Data_type1));
    debug_printf(a);
    debug_printf(b);
    debug_printf(c);

    a = debug_struct_member_offset(Data_type2,a);
    b = debug_struct_member_offset(Data_type2,b);
    c = debug_struct_member_offset(Data_type2,c);
    debug_printf(sizeof(Data_type2));
    debug_printf(a);
    debug_printf(b);
    debug_printf(c);
}

64位ubuntu gcc

可以看到两个结构体里的成员变量类型相同,但是顺序不同。因为数据对齐的规则,最后俩个结构体所占空间大小不同。

eg;数组和字符串作为结构体成员,并不是按照数组长度或字符串长度进行对齐。

typedef struct data_type3{
    char a;
    char b;  
    char c;
} Data_type3;
typedef struct data_type4{
    char a;
    char b[2];  
} Data_type4;

 比如上面两个结构体占用的字节大小都i是3

3、对对齐规则进行干涉的方法

(1)使用prama pack(value)伪指令

(2)使用__attribute((aligned(n))),操作对象为结构体时,是对结构体的对齐值修改为n

(3)位域

#include <stdio.h>
#include <stdlib.h>

#define debug_printf(value) printf(#value ": %d\n",value)
#define debug_struct_member_offset(struct, member) (((char*)(&(((struct *)0)->member)))- ((char *)0))//结构体成员相对结构体起始地址偏移量


#pragma pack(4)  //4字节对齐开始,对齐大小只能比4小,不能大
typedef struct
{
  int a;     
  double b;
} test_t;
/*4字节对齐,所以即使b是double类型,偏移地址是4而不是8*/
#pragma pack()//字节对齐结束

typedef struct
{
  char  a;    
  short b;    
}__attribute__((packed)) test_t1; //按实际空间 
typedef struct
{
  char  a;    
  short b;    
}__attribute__((aligned(4))) test_t2;
typedef struct
{
  char  a;    
  short b;   
}__attribute__((aligned(8))) test_t3;
typedef struct
{
  char  a;    
  short b;   
}__attribute__((aligned(16))) test_t4;


int main(void)
{
	
	int a,b,c;
	
	a = debug_struct_member_offset(test_t,a);
	b = debug_struct_member_offset(test_t,b);
	debug_printf(sizeof(test_t));
	debug_printf(a);
    debug_printf(b);

	a = debug_struct_member_offset(test_t1,a);
	b = debug_struct_member_offset(test_t1,b);
	debug_printf(sizeof(test_t1));
	debug_printf(a);
    debug_printf(b);

	a = debug_struct_member_offset(test_t2,a);
	b = debug_struct_member_offset(test_t2,b);
  	debug_printf(sizeof(test_t2));
	debug_printf(a);
    debug_printf(b);

	a = debug_struct_member_offset(test_t3,a);
	b = debug_struct_member_offset(test_t3,b);
  	debug_printf(sizeof(test_t3));
	debug_printf(a);
    debug_printf(b);

	a = debug_struct_member_offset(test_t4,a);
	b = debug_struct_member_offset(test_t4,b);
  	debug_printf(sizeof(test_t4));
	debug_printf(a);
    debug_printf(b);
	
	
	return 0;
}

 扩展:attribute可以设置函数属性、变量属性和类型属性

对于属性(主要是函数属性)主要设置的关键字有
alias:设置函数别名
aligned:设置对齐方式
constructor/destructor:主函数执行之前、之后执行的函数
format:指定变参函数的格式输入字符串所在函数位置以及对应格式输出的位置
noreturn:指定这个函数没有返回值

 例如:在main函数执行前和执行后运行的函数

#include <stdio.h>

void before() __attribute__((constructor));
void after() __attribute__((destructor));

int main(void)
{
	printf("this is function %s\n",__FUNCTION__);
	return 0;
}

void before(){
	printf("this is function %s\n",__FUNCTION__);
	return;
}

void after(){
	printf("this is function %s\n",__FUNCTION__);
	return;
}

4、位域

出现于结构体或共用体的定于中,形式如下

struct student
{
	int sex : 1;
    int id : 7;
    int score : 8; 
};

在结构体student中,成员变量sex占用空间位1位,id7位,score8位。

其中,位域的值必须小于变量类型的宽度。比如int类型成员变量的位域值必须是1~31之间的整数

位域的填充规则

1、如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
2、如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
3、如果相邻的两个位域字段的类型不同,则各个编译器的具体实现有差异。不压缩方式,采用前面所讲的字节对齐方式。
4、整个结构体的对齐方式使用结构体的有效对齐参数值。
5、如果位域字段之间穿插着非位域字段,则不进行压缩,该字段采用字节对齐。
6、无名的位域不能使用,只能用于填充,位宽为0表示强制下一位域对齐到当前类型的边界。

2、字节序

大端小端的概念是面向多字节数据裂隙的存储方式定义的

小端就是低位在前(”前“是指靠近内存低地址),既低位字节存储在内存低地址,字节高低顺序与内存高低顺序相同。

大端就是高位在前。

网络字节序规定是大端模式,即高字节先走。

#include <stdio.h>
int byteorder()
{
	int a = 1;
	return *(char*)&a;
}

int main(void)
{
	int ret = byteorder();
	if( ret == 1 )
		printf("小端\n");
	else
		printf("大端\n");
	return 0;
}

不同的cpu有不同的字节序类型,我们常用的x86和arm架构都是采用小端存储。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

字节对齐和字节序 的相关文章

随机推荐

  • moviepy音视频剪辑:视频半自动追踪人脸打马赛克

    一 引言 在 moviepy1 03音视频剪辑 使用manual tracking和headblur实现追踪人脸打马赛克 介绍了使用手动跟踪跟踪人脸移动轨迹和使用headblur对人脸进行打马赛克 实际上 moviepy除了使用manual
  • windows服务启动失败解决流程

    最近遇到windows服务启动失败的情况 网上查阅了一下相关的解决方式 顺便记录一下解决的一般流程和方式 一般是软件的配置文件出现问题 先检查配置文件是否有问题 例如没有符合yml格式 不可使用tab键而是空格键 等细节问题 1 查看相关应
  • C++const限定符

    最近通过网络资料复习const 后通过跟专业书籍对比 发现网络上很多都存在一些错误 于是在此做个笔记 1 const定义常量 一旦创建后其值就不能再改变 所以其必须初始化 若用表达式初始化 那么会在运行时初始化 若用值初始化 则在编译阶段初
  • 完美解决sqlalchemy.exc.ObjectNotExecutableError: Not an executable object

    报错的程序如下 from sqlalchemy import create engine import pandas as pd engine create engine mysql pymysql root 123456 localhos
  • 双极性正弦脉宽调制(双极性SPWM)介绍及MATLAB仿真验证

    前言 本文介绍单相全桥逆变电路双极性正弦脉冲宽度调制 双极性SPWM 并用MATLAB仿真验证 并且通过对比逆变器滤波前后效果 突出了SPWM谐波高频化 便于滤除的显著特点 希望本文对大家有帮助 文末有仿真模型代码 有需要自取 目录 前言
  • PM2常用命令

    安装pm2 npm install g pm2 1 启动 1 pm2 start app js 2 pm2 start app js name my api my api为PM2进程名称 3 pm2 start app js f name
  • chatgpt赋能python:如何用Python求和

    如何用Python求和 Python是一种高级编程语言 最初设计用于简单的脚本编写 但是也可以用于复杂的科学计算 求和是我们在编程中经常需要处理的基本操作之一 Python具有简单易学的语法和广泛的开源库 使其成为处理数据的强大工具 在本文
  • 2022CISCNmisc

    ez usb 题目已经告诉是usb流量 一共有三个地址2 8 2 10 2 4但2 4没用 我们分别导出2 8和2 10 从网上搜usb脚本将他们两个分别解出来 将那一打穿放到010发现是个rar文件 但是损坏了打不开 可以用winrar修
  • bp神经网络的训练方法,一文搞定bp神经网络

    BP人工神经网络方法 一 方法原理人工神经网络是由大量的类似人脑神经元的简单处理单元广泛地相互连接而成的复杂的网络系统 理论和实践表明 在信息处理方面 神经网络方法比传统模式识别方法更具有优势 人工神经元是神经网络的基本处理单元 其接收的信
  • -day17 面向对象基础

    第三模块 面向对象 网络 并发编程 此模块包含如下三大部分知识 面向对象 Python中支持两种编程方式来写代码 分别是 函数式编程 面向对象式编程 函数式 定义函数 在函数中实现功能 def func print 一个功能 执行函数 fu
  • mysql高可用分库分表ShardingSphere之Sharding-proxy

    文章目录 一 ShardingSphere 1 1 官网地址说明 1 2 为什么分库分表 二 官网整合说明 1 1 下载sharding proxy 1 2 sharding proxy集成注册中心 1 3 查看配置手册 1 3 1 官网数
  • C++ 快速排序

    快速排序是比较常用的一种排序 平均时间复杂度为O nlogn 最坏的时间复杂度为O n 话不多说 上代码 include
  • [Python人工智能] 三十三.Bert模型 (2)keras-bert库构建Bert模型实现文本分类

    从本专栏开始 作者正式研究Python深度学习 神经网络及人工智能相关知识 前一篇文章开启了新的内容 Bert 首先介绍Keras bert库安装及基础用法 这将为后续文本分类 命名实体识别提供帮助 这篇文章将通过keras bert库构建
  • 【C++】异常

    需要云服务器等云产品来学习Linux的同学可以移步 gt 腾讯云 lt gt 阿里云 lt gt 华为云 lt 官网 轻量型云服务器低至112元 年 新用户首次下单享超低折扣 目录 一 异常 1 C语言处理异常的方式 2 C 处理异常的方式
  • MyBatis 中if 标签 判断字符串不生效

    今天遇到if 标签判断字符串不生效 导致查询结果错误 异常sql 的mapper 文件
  • Ubuntu14.04安装ssh实现远程登陆

    Ubuntu14 04安装ssh实现远程登陆 安装 sudo apt get install y ssh 修改ubuntu的ip地址和PC在同一网段内 配置 sudo gedit etc ssh sshd config 修改成如下设置 重启
  • C++给变量起别名

    以下代码展示给变量a取一个别名b 两者指向同一个内存空间位置 改变b a也会相应改变 include
  • AR模型脱卡,unity端实现步骤详情

    AR模型脱卡unity端实现具体步骤 AR模型脱卡的原理 利用一些unity端AR插件做AR应用 通常会有一个需求 当识别物消失的时候 将3D模型从识别物这个父物体上移除 显示在屏幕中央 那么原理就显而易见了 就是在识别物追踪方法中 写一些
  • Pytorch固定部分参数(只训练部分层)

    参考 https www cnblogs com jiangkejie p 11199847 html 在迁移学习中我们经常会用到预训练模型 并在预训练模型的基础上添加额外层 训练时先将预训练层参数固定 只训练额外添加的部分 完了之后再全部
  • 字节对齐和字节序

    1 字节对齐 1 什么是字节对齐 内存空间是按字节划分 理论上可以从任意起始地址访问任意类型的变量 但实际上在访问特定类型变量是经常在特定的内存地址访问 这就需要各种数据类型按照一定的规则进行排列 而不是一个接一个紧接着排放 简单的讲就是数