二谈内存对齐

Golang的内存对齐 Golang的内存对齐测试demo:内存对齐为什么要关心对齐为什么要做对齐默认对齐系数成员对齐:整体对齐对齐规则分析流程成员对齐整体对齐结果小结巧妙的结构体分析流程成员对齐整体对齐结果总结 测试demo: 我们先来看一个demo: type Part1 struct { a bool b int32 c int8 d int64 e byte } 我们先来看一下Part1里面的各个数据... 阅读详情

 转者注: 这续集写得比第一集还要差,本来不想转的,但看到他写了那么长,就顺便转来看一下

 

版权声明 :转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://bigwhite.blogbus.com/logs/2661330.html

关于内存对齐的话题,始终是敏感的。稍有不慎,必将闯下大祸!最近项目稍显轻闲,自己给自己安排一天反思和总结一下,突然想到以前写过的一篇'也谈内存对齐 ',那篇文章谈的是内存对齐的基本知识以及一些实验的数据,想必很多人看完后,会收获一些东西,但是对内存对齐的应用还是处于懵懂状态,其实大部分时间我们是不会显式的用到'内存对齐的',但是有些时候我们需要这样做。这里做了一个小例子,希望能给大家以启发。

例 子是这样的:我们有一种二进制文件,其中存储了多条经过特定对齐的某种记录格式的数据,我们的任务就是解析出来这些数据,但是我们不知道也没有这种数据的 记录格式结构的定义,但我们不是一无所有,我们有一个表,这个表描述了这个记录格式中有哪些域以及这些域的类型信息,我们还知道的是源数据的对齐系数。

叙述完问题后,我们来给出一些具体的东西:

二进制文件生成程序:
#pragma pack(1)
struct foo_t {
        int     a;
        char    b[25];
        int     c;
};
#pragma pack()

int main() {
        FILE            *fp     = NULL;
        struct foo_t    foo1    = {12457, "test foo1", 75421};
        struct foo_t    foo2    = {36098, "test foo2", 89063};

        fp = fopen("foo.dat", "wb+");
        if (fp == NULL) {
                printf("error in open foo.dat!/n");
        }

        fwrite(&foo1, sizeof(foo1), 1, fp);
        fwrite(&foo2, sizeof(foo2), 1, fp);

        fclose(fp);

        return 0;
}

生成的待解析文件:foo.dat,其中有两条记录。

好了,我们的任务已经很明确了,就是正确解析出这两条记录。如果解析程序知道有下面这样的结构体定义:
#pragma pack(1)
struct foo_t {
        int     a;
        char    b[25];
        int     c;
};
#pragma pack()
那这里也就不用说废话了,我们不知道这个结构定义,不过我们通过知道的一些信息可以整理出一个描述该结构定义的一个表:

#define X_CHAR          1
#define X_STRING        2
#define X_INT           3

typedef struct x_fld_info_t {
        char    name[MAX_FIELD_NAME_LEN];
        int     type;
        int     nitems;
        int     offset;
} x_fld_info_t;

x_fld_info_t    cpi_type_info_tab[3] = { /* cpi - composite */
        {"a", X_INT, 1, -1},
        {"b", X_STRING, 25, -1},
        {"c", X_INT, 1, -1}
};

想 一想,我们能从文件foo.dat中读出来什么?仅仅是一块数据,每次读多大一块?如何在这块数据中找到相应的域呢?没错,我们需要通过 cpi_type_info_tab这个表信息得出每条foo_t记录的大小,还要得到foo_t中每个域在这块数据中的偏移量,然后根据偏移量和域自身 大小准确获取其内容。

好了终于要用到内存对齐的知识了,其实想想也知道foo.dat的文件生成程序和我们的解析程序可能不在一台机器上, 而且完全可能在体系结构不同的机器上,这样不同体系结构的机器他们的默认对齐系数、字节序都可能不同(这里我们暂不考虑字节序的问题),我们在文件生成程 序那边强制指定对齐系数有利于解析程序这边的解析。我们要做的就是根据已知的对齐系数和cpi_type_info_tab表中的信息计算出来该结构体在 特定对齐系数下的总大小以及其各个域的偏移量。下面的宏X_ROUND_UP和函数align_cpi_type配合完成了这一工作:

int x_atom_type_size[4] = {
        -1,
        sizeof(char),
        sizeof(char),
        sizeof(int)
};

static int lg2(int k) { /* 这里假设k一定为2的次方^_^ */
        int     i = 0;

        while ((k /= 2) != 0) {
                i++;
        }
        return i;
}

#define X_ROUND_UP(x, k, rv) do { /
                unsigned int t = (-1 << k); /
                (rv) = ((x - t - 1) & t); /
        } while(0)

static void align_cpi_type(x_fld_info_t *tab, int fld_cnt, int force_align_mod, int *size) {
        int     i       = 0;
        int     cur     = 0;
        int     rv      = 0;
        int     max_sz  = 0; /* 复合类型各个域中的最大原子类型的长度, 用于对齐整个结构 */
        int     atom_sz = 0; /* 域的原子类型 */
        int     ali_mod = 0; /* alignment modules */

        /*
         * 对齐各个域
         */
        for (i = 0; i < fld_cnt; i++) {
                atom_sz = x_atom_type_size[tab[i].type];
                if (max_sz < atom_sz) {
                        max_sz = atom_sz;
                }

                if (atom_sz < modules) {
                        ali_mod = atom_sz;
                } else {
                        ali_mod = force_align_mod;
                }

                X_ROUND_UP(cur, lg2(ali_mod), rv);
                tab[i].offset = rv;
                cur += (atom_sz * (tab[i].nitems));
        }

        /*
         * 对齐整个复合类型
         */
        if (max_sz < force_align_mod) {
                ali_mod = max_sz;
        } else {
                ali_mod = force_align_mod;
        }

        X_ROUND_UP(cur, lg2(ali_mod), rv);
        (*size) = rv;
}

如果对内存对齐还有疑惑的,可以去看看我的那篇'也谈内存对齐 ',再回到这来看align_cpi_type的实现,这里的X_ROUND_UP的算法借自于'Hacker's Delight ' 一书,很好的一本讨论'Computer Arithmetic'的书,里面的很多Knowledge & Tip很有价值。通过align_cpi_type函数我们既得到了结构的大小也得到了结构中各个域的偏移量。根据这些信息我们就可以输出文件 foo.dat中的数据了。

static void output_cpi_mem(x_fld_info_t *tab, int fld_cnt, char *buf)
{
        int     i = 0;
        int     int_tmp = 0;
        char    str_tmp[50]; /* 这里仅是举例, 所以使用了一个固定大小的缓冲区, 实际上需要做一个可动态扩展的缓冲区 */

        for (i = 0; i < fld_cnt; i++) {
                if (tab[i].type == X_STRING) {
                        memset(str_tmp, 0, sizeof(str_tmp));
                        memcpy(str_tmp, (char*)(buf+(tab[i].offset)), x_atom_type_size[tab[i].type] * (tab[i].nitems));
                        printf("the value of field '%s' is [%s]/n", tab[i].name, str_tmp);
                } else if (tab[i].type == X_INT) {
                        memcpy(&int_tmp, (char*)(buf+(tab[i].offset)), x_atom_type_size[tab[i].type] * (tab[i].nitems));
                        printf("the value of field '%s' is [%d]/n", tab[i].name, int_tmp);
                }
        }
}

int main() {
        x_fld_info_t    cpi_type_info_tab[3] = { /* cpi - composite */
                {"a", X_INT, 1, -1},
                {"b", X_STRING, 25, -1},
                {"c", X_INT, 1, -1}
        };

        int     size = 0;
        int     i    = 0;

        align_cpi_type(cpi_type_info_tab, sizeof(cpi_type_info_tab)/sizeof(cpi_type_info_tab[0]), modules, &size);

        /*
         * 从文件foo.dat中读出所有记录
         * 并打印出来
         */
        FILE    *fp     = NULL;
        char    buf[50];


        fp = fopen("foo.dat", "r");
        if (fp == NULL) {
                printf("error in fopen!/n");
        }

        for (i = 0; i < 2; i++) { /* 这里偷了个懒儿,直接用2这个记录的个数了 */
                memset(buf, 0, sizeof(buf));
                fread(buf, size, 1, fp);

                /*
                 * 通过cpi_type_info_tab中的信息打印出
                 * 各个字段的值
                 */
                output_cpi_mem(cpi_type_info_tab, 3, buf);
        }

        fclose(fp);

        return 0;
}

执行输出:
the value of field 'a' is [12457]
the value of field 'b' is [test foo1]
the value of field 'c' is [75421]
the value of field 'a' is [36098]
the value of field 'b' is [test foo2]
the value of field 'c' is [89063]

看到这有些人可能还是很糊涂,到底为什么要这么做呢?提示一下:现在我们要解析一存储未知类型数据的文件的记录时,我们只需要这个纪录的一些描述信息即可了,而无需知道那个foo_t的具体定义了。能不能理解就看你自己了。

内存对齐的理解 一、内存对齐物理层面的理解 内存物理结构 我们来了解一下内存的物理构造,一般内存的外形图片如下图: 一个内存是由若干个黑色的内存颗粒构成的。每一个内存颗粒叫做一个chip。每个chip内部,是由8个bank组成的。其构造如下图: 而每一个bank是一个二维平面上的矩阵,矩阵中每一个元素中都是保存了1个字节,也就是8个bit。 内存编址方式 那么对于我们在应用程序中内存中地址连续的8个字节,例如0x0000-0x0007,是从位于bank上的呢?直观感觉,应该是在第一... 阅读详情

相关推荐

绕开华为通道,获取解锁码解锁BootLoader

刷机有风险,操作需谨慎,如果因为各种因素导致手机变砖无法开机,本教程概不负责,望悉知 前言 这篇文章的大多内容是根据我自己找的一篇文章《绕开华为通道,获取解锁码解锁BootLoader》来编写的,里面的大部分内容是文章的原内容。下面的都是我参考文章中做了一些小部分的修改,增加了我华为P8手机的一些操作,下面开始讲述我的解锁过程。 因为华为官方在2018年的七八月份吧,关闭了解锁码的申请通道,这...

Martin.Mu `s Special Column 5万+

内存对齐、内存对齐规则解释、内存对齐原理

一、内存对齐的原因 我们都知道计算机是以字节(Byte)为单位划分的,理论上来说CPU是可以访问任一编号的字节数据的,我们又知道CPU的寻址其实是通过地址总线来访问内存的,CPU又分为32位和64位,在32位的CPU一次可以处理4个字节(Byte)的数据,那么CPU实际寻址的步长就是4个字节,也就是只对编号是4的倍数的内存地址进行寻址。同理64位的CPU的寻址步长是8字节,只对编号是8的倍数的内存...

草帽~小子^的博客 7393

Colmap中 patchmatch源码

惊世骇俗的Colmap PatchMatch源码 500多行,简明易懂 先了解PatchMatch的options: max_image_size: 任一维度的最大图像尺寸 gpu_index: gpu的下标 depth_min,depth_max: 随机采样的深度范围 window_radius:用于计算NCC(两图片的归一化互相关),NCC的计算需要用到 win_size. 图像匹配 | NCC 归一化互相关损失 | 代码 + 讲解 - 知乎 (zhihu.com) window_step: 用.

qq_24884193的博客 2209

内存对齐详解

为什么要进行内存对其? (1)空间原因:没有进行内存对齐的结构体或类会浪费空间。 (2)性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。 (3)平台原因:不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。 如果一个变量的内...

Tyler_Zx的博客 1万+

SpringBoot实战——仿b站项目(一)

热部署就是当应用程序这种运行的时候升级冉家或者修改某一部分代码、配置文件时,无需手动启动应用,即可修改的部分生效工具 + IDEA配置。

weixin_52880572的博客 3455

Ultrascale/Ultrascale+ FPGA GTH IP及结构详解(一)

FPGA GTH Transceiver

houzi6320的博客 1万+

结构体内存对齐

int a;char b;char c;char b;int a;char c;思考一下node1和node2的大小分别为多少?我是在 Windows 下 MinGW32 的 GCC 测试的一样的成员属性,但node1只有 8K,而node2的大小却有 12K。由此可见,结构体对齐,实质上就是内存对齐。

Projectsauron 的博客 2万+

恶意流量检测数据集

对当前公开的恶意流量相关数据集进行归类总结,持续更新相关论文

tyutwuxuan的博客 1940

也谈内存对齐

 转者注:虽然本文写得不太好,但是见到写得这么长就顺便转来看一下 版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明http://bigwhite.blogbus.com/logs/1347304.html在最近的项目中,我们涉及到了“内存对齐”技术。对于大部分程序员来说,“内存对齐”对他们来说都应该是“透明的”。“内存对齐”应该是编译器的“管辖范围”

olncy的专栏 619

Mac上除了Homebrew,这几种安装ADB的方法你可能也需要知道(含手动配置避坑)

本文全面解析Mac上五种ADB安装方案,从Homebrew到手动配置,涵盖常见问题解决与环境变量配置。特别针对macOS High Sierra等老旧系统提供专属解法,帮助开发者高效安装Android Debug Bridge(ADB),避免常见陷阱,提升开发效率。

weixin_42546392的博客 320

基于BenchmarkSQL的达梦数据库TPCC性能测试

中的用户和密码在达梦数据库中创建测试用户,并保证其表空间足够容纳生成的测试数据。如果开启了归档,还要考虑归档日志占用的空间。BenchmarkSQL默认不支持达梦数据库。这里我们让BenchmarkSQL把达梦数据库当作Oracle即可。Oracle数据库对应的测试配置文件为。是使用BenchmarkSQL进行性能测试的主要配置文件。是生成的测试报告,png文件是报告中包含的图片。拷贝达梦数据库驱动到BenchmarkSQL的。测试结束后,会在当前路径下生成一个以。规则命名的结果目录。

Sebastien23的博客 2634

C++ 内存对齐

二、内存对齐规则 首先了解两个概念: 1.每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。32位系统,gcc中默认#pragma pack(4),可以通过预编译命令#pragma pack(n),n = 1,2,4,8,16来改变这一系数。 2.有效对齐值:是给定值#pragma pack(n)和结构体中最长数据类型长度中较小的那个。有效对齐值也叫对齐单位。 然后明确内存对齐的两个规则: 1.结构体第一个成员的偏移量(offset)为0,以后每个成员相对于结构体首地址的 off

weixin_43816121的博客 4904

8.2 发展趋

分子泵技术正处在一个快速变革的时代,面对日益增长的应用需求和不断涌现的技术挑战,其发展呈现出多元化、智能化和高度集成化的趋势。这些发展趋势不仅代表着技术创新的方向,也预示着分子泵在未来工业体系中将要扮演的更加重要的角色。

技术工作者 113

什么是内存对齐以及作用

什么是内存对齐? 为了解释这个问题,先来介绍下面的例子: #include<iostream> using namespace std; struct A { char a; short b; int c; }; struct B { short b; int c; char a; }; int main() { cout<<sizeof(A)&...

qq_41909314的博客 6096

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

从Eigen向量化谈内存对齐

作者丨王金戈@知乎(已授权)来源丨计算机视觉SLAM编辑丨realcat缘起Eigen是一个非常常用的矩阵运算库,至少对于SLAM的研究者来说不可或缺。然而,向来乖巧的Eigen近来却频频...

3D视觉工坊 1225

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

再谈内存对齐

一、问题提出 怎样的数据访问是对齐的?很简单 aligned: C内存地址%数据大小 ==0;自然对齐 unaligned:不满足上述规则,这个数据是非对齐的 简单的说,就是char类型无对齐要求;short类型的数据地址最后一位是0;int型数据地址最后两位为0; 非对齐访问对X86//Sparc这类芯片会导致访问开销问题,对于ARM/MIP/ACPHA/IA-64这类CPU会导致异常。 本文的所有讨论基于32位的RISC/CISC CPU和GCC编译器 二、对齐处理 内存对齐的几个处理场

缘起宇轩阁 1020

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

三谈内存对齐

转者注:看到这样的排版真让人恶心到极点...不过见到原作者写了那么长就顺便转来看一下 版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明http://bigwhite.blogbus.com/logs/3990258.html记得以前曾经两次谈到过内存对齐话题,一次在也谈内存对齐一文中,另一次则是也谈内存对齐(续),今天下午和同事又谈到

olncy的专栏 734

关于内存对齐的那些事

Wrote by mutouyun. (http://darkc.at/about-data-structure-alignment/) 1. 内存对齐(Data Structure Alignment)是什么 内存对齐,或者说字节对齐,是一个数据类型所能存放的内存地址的属性(Alignment is a property of a memory address)。 这个属性

云彩挂上的二叉树 1万+

C语言 | 内存对齐01 - 什么是内存对齐

一、前言 在单片机下使用C语言编程时,内存对齐的知识点必须掌握。掌握内存对齐后,可以防止内存碎片化,单片机有限的内存被更加有效地使用。 二、内存对齐 先看如下代码: 结构体Test1占用了多少字节?如果事先不知道内存对齐的话,答案肯定是:1个字节(char)+ 4个字节(int)+ 1个字节(char) = 6个字节。 事实上,Test1结构体占用了12个字节,从DEBUG模式下Watch1观察: OK,不就猜少了12个字节吗?有什么影响吗?先不说影响吧,咱们先来看看单片机内存里的实际情况。从上图看

wallace89的博客 2682

新手谈对象内存布局与内存对齐

       对于对象的内存布局与内存对齐这个问题,其实是没有统一的说法的,因为实际情况还要联系你的平台与编译器以及编译器的设置。我的是VC7,XP系统,编译器的结构成员对齐设置为默认。下面针对两种情况来说说:       在没有虚拟函数的情况下。对象的内存布局比较简单。看下面的类:       class       A{              public: int m_a;       

isaf的专栏 4669

什么是内存对齐

内存对齐

qq_42376419的博客 1535

关于内存对齐

第一个问题:什么是内存对齐?为什么要内存对齐?内存对齐(Memory Alignment)是计算机科学中的一个概念,指的是将数据存储在特定的内存地址上,以提高系统性能。内存对齐的主要目的是使数据访问更快、更有效率以及更好的缓存优化。内存对齐的根本原因:对当前因地址总线限制而导致的内存寻址“不自由”的一种“妥协”。寄存器只能从整除以4的地址开始读取数据,因此内存对齐能够在一定程度上减少读取数据的次数。内存地址:计算机内存是由一系列连续的地址组成的,每个地址对应一个字节。对齐要求。

weixin_45484608的博客 1946

内存对齐以及如何关闭内存对齐

内存对齐以前接触过,知道有这么回事,昨天面试,面试官问了一个结构体内存分配相关的问题: struct _A{ int a; int b; char c; }A; sizeof(A)=?(32位机器) 我一想这要涉及到内存对齐啊,sizeof(A)=12 啊, 没想到接下来面试官的一个问题就是:那如果我想节省内存,不让他内存对齐,就分配9个字节,怎么办? 当时就蒙了,一直没想过这个

a1205137569的博客 4358

【golang】内存对齐

在访问特定类型变量的时候通常在特定的内存地址访问,这就需要对这些数据在内存中存放的位置有限制,各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。内存对齐是编译器的管辖范围。表现为:编译器为程序中的每个“数据单元”安排在适当的位置上。

m0_53328239的博客 1474

关于内存对齐你需要了解的事

这篇文章的目的是带你了解什么是内存对齐,具体的内存对齐的细节、处理方式、不同架构则不会去详细讲解,只做科普文用。内存对齐和数据在内存中的位置有关。内存对齐以字节为单位进行,一个变量的内存地址如果正好等于它的长度的整数倍,则称为自然对齐。比如在32位 cpu 下,一个 u32 的内存地址为0x00000004 ,则属于自然对齐。内存空间按照字节进行划分,理论上可以从任意地址开始读取,实际上会要求读取数据的首地址是某一个值的整数倍。

日常学习记录 3406
上一篇: 也谈内存对齐
下一篇: 三谈内存对齐
olncy
博客等级 码龄20年 30粉丝 37原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值