查看原文
其他

MATLAB程序设计语言(3.2)---一切皆为数组2(MATLAB的底层实现)

洞穴之外之编程哥 理念世界的影子 2021-06-23

公众号:理念世界的影子

文不可无观点,观点不可无论据。

转载请注明出处



MATLAB功能强大,编程方便,是国际广泛使用的计算软件。目前已有很多书籍介绍其在工程上的应用,但很少有从程序设计语言的角度写的书或文章。


MATLAB的核心之处为其一切皆为数组的设计,我们将继续从内存中数据存储的研究展示这一点。


通过上述几个mex程序,对MATLAB储存格式进行较为底层的、直观的解析。


  1. a=[];

  2. b=zeros(1,1);

  3. c=zeros(3,1);

  4. d=zeros(3,4,5,6);

  5. disp('a:'); dispmem(getaddr(a), 56);

  6. disp('b:'); dispmem(getaddr(b), 56);

  7. disp('c:'); dispmem(getaddr(c), 56);

  8. disp('d:');s=dispmem(getaddr(d), 56);


输出

此处贴出的输出中加粗部分。32位MATLAB程序的mxArray的17~20字节处变量代表了数组维度,其中空数组(0维)、1维、2维在MATLAB中均视为二维矩阵,29~32字节,以及33~36字节处给出了维度信息。

对于多维矩阵,在MATLAB中输入


1. dispmem(uint64(hex2dec('0d801710'), 16);  % 字符串需与d矩阵输出的地址一致,或者使用s((8-1)*8+[7 8 5 6 3 4 1 2])代替


将输出

03 00 00 00 04 00 00 00  05 00 00 00 06 00 00 00


正好是d矩阵各维度信息。MATLAB中的sub2ind、ind2sub、reshape、size、length、numel,以及isempty函数,均是根据这些信息进行操作的。而数据本身是不更改的。

输入

1. posn=@(n) (n-1)*8+[7 8 5 6 3 4 1 2];

2. a=int8([3+4*sqrt(-1) 5+6*sqrt(-1)]);

3. disp('a: ');s=dispmem(getaddr(a), 56);

4. disp('Re: ');dispmem(uint64(hex2dec(s(posn(10)))), 2);

5. disp('Im: ');dispmem(uint64(hex2dec(s(posn(11)))), 2);


输出

即32位MATLAB的mxArray的37~40字节显示了数组的实部的地址,41~44字节显示了数组的虚部的地址。MATLAB存储中,复数的实部和虚部是分开存储的。再测试


1. a=[1 2;3 4;5 6];

2. b={1 2;3 4;{5 6} {}};

3. c=struct('a', a);

4. disp('a: ');dispmem(getaddr(a), 56);

5. disp('b: ');dispmem(getaddr(b), 56);

6. disp('c: ');dispmem(getaddr(c), 56);


输出


看起来在32位程序中,第4字节到第8字节代表不同的数据类型,其中06为矩阵(更确切地为双精度矩阵)、04为字符串、01为元胞数组、02为结构体、10为函数。其实还不止。在MATLAB安装目录/extern/include/matrix.h有清晰的定义。


/**

 * Enumeration corresponding to all the valid mxArray types.

 */

typedef enum

{

    mxUNKNOWN_CLASS = 0,

    mxCELL_CLASS,

    mxSTRUCT_CLASS,

    mxLOGICAL_CLASS,

    mxCHAR_CLASS,

    mxVOID_CLASS,

    mxDOUBLE_CLASS,

    mxSINGLE_CLASS,

    mxINT8_CLASS,

    mxUINT8_CLASS,

    mxINT16_CLASS,

    mxUINT16_CLASS,

    mxINT32_CLASS,

    mxUINT32_CLASS,

    mxINT64_CLASS,

    mxUINT64_CLASS,

    mxFUNCTION_CLASS,

    mxOPAQUE_CLASS,

    mxOBJECT_CLASS, /* keep the last real item in the list */

#if defined(_LP64) || defined(_WIN64)

    mxINDEX_CLASS = mxUINT64_CLASS,

#else

    mxINDEX_CLASS = mxUINT32_CLASS,

#endif

    /* TEMPORARY AND NASTY HACK UNTIL mxSPARSE_CLASS IS COMPLETELY ELIMINATED */

    mxSPARSE_CLASS = mxVOID_CLASS /* OBSOLETE! DO NOT USE */

}

mxClassID;


即MATLAB使用一套数据结构,对所有的类型进行了枚举和区分(在C语言中,enum从第一个数字进行加1累积计数),可惜的是,作者未能在MATLAB的头文件中找到mxArray结构的定义。

上面的程序中一个个输入命令查找太麻烦,为方便解析,利用MATLAB显示函数disp的功能,将指针解析为超链接,便可以点击超链接遍历内存块内容。首先,更改之前的dispmem.cpp,删除其中的mexPrintf循环,并命名为getmem.cpp,编译。再编写超链接生成函数如下。


dispmem_href.m


  1. function dispmem_href(addr, nbyte)

  2. % 显示带超链接的头信息,超链接按指针长度得到(可能不正确)

  3. % addr为uint64的头地址,nbyte为显示的字节数,如不输入,则认为为mxArray大小

  4. [c maxsize endian]=computer; % 得到计算机信息

  5. if(strcmpi(c, 'pcwin') || strcmpi(c, 'glnx86')) nbit=32; % 32位

  6. else nbit=64;end

  7. if(nbit==32)

  8.     if(strcmpi(endian, 'L')) norder=[7 8 5 6 3 4 1 2]; % big median

  9.     else norder=1:8;end

  10.     len=56;

  11. else

  12.     if(strcmpi(endian, 'L')) norder=[15 16 13 14 11 12 9 10 7 8 5 6 3 4 1 2];

  13.     else norder=1:16;end

  14.     len=104;

  15. end

  16. if(nargin==2) len=nbyte;end

  17. haddr=lower(dec2hex(addr, nbit/4)); % 将addr解析为hex

  18. disp([haddr(norder),':']);

  19. context=getmem(addr, len); % 得到内容

  20. str=[];

  21. for i=0:nbit/4:len*2-1

  22.     s=context(i+(1:nbit/4)); % 按指针长度截取内容

  23.     if( i~=0 && mod(i, nbit)==0) str=[str sprintf('\n')];end  % 回车

  24.     str=[str, sprintf('<a href="matlab: dispmem_href(uint64(hex2dec(''%s'')),%d)">%s</a>  ', s(norder), len,  s)];  % 增加超链接

  25. end

  26. disp(str);

  27. disp(sprintf('----------------------------------------<a href= "matlab: clc; dispmem_href(uint64(%d), %d)">******</a>', addr, len)); % 清屏仅显示本项



如果读者有较多时间,可以寻找或采用各种数据进行一一测试,相信可以大部分还原其信息。下图为笔者还原的部分信息。

32位部分MATLAB数据头信息


以上进行了初步热身,这些看起来碎片化的信息,了解它,可以理解MATLAB部分函数语法,可以编写效率更高、更为合理的程序。






往期文章:

MATLAB

MATLAB程序设计语言(3.1)---一切皆为数组1

MATLAB程序设计语言(2.1)---变量的作用域

MATLAB程序设计语言(2)---help的see also与六度空间理论

MATLAB程序设计语言(1)---入门


微信扫一扫

关注“理念世界的影子”

版权声明:本文是"洞穴之外"作者原创文章,欢迎转载,须署名并注明来自“理念世界的影子”公众号。


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存