关于结构体这个字眼,对于我们这些从事编程工作的人来讲,熟悉得不能再熟悉了。当然,结构体也是需要掌握的重中之重。不论是C/C++,还是matlab,结构体都占据着重要的一环。结构体属于构造类型,就像生活中用来整理生活用具的盒子,只是它装的是数据类型而已。通过使用结构体,可以为程序设计带来很多便利。在此,将介绍matlab结构体的使用,包括结构体的基本用法、结构体在GUI设计中的应用以及C-MEX文件生成结构体等。
1、结构体的基本用法
对于结构体的基本用法而言,主要涉及结构体创建和常见结构体函数使用两个部分。其中,关于结构体的创建,matlab有以下两种创建方式:
a.使用点(.)运算符。如图1-(a)所示。
b.使用struct函数创建结构体。如图1-(b)所示。
以下为常用结构体函数:
1、isfield() % 检查结构体中是否含有某一字段名的字段
2、refield() % 从结构体中移出特定的字段
3、struct2cell() % 将结构体转换成单元数组
4、fieldnames() % 返回结构体的字段名,或对象的属性名
5、isstruct() % 检查某一数据是否为matlab结构体
2、结构体在GUI设计中的应用
Matlab结构体在程序设计中的使用频率相对较高,尤其是在GUI设计中最为常见。其中最常见、也是最重要的一个结构体便是handles结构。handles结构体作为一种重要的GUI数据管理机制,用于保存所有GUI对象数据。它是在运行GUIDE创建GUI时,由M文件自动生成的一种结构体。通常作为GUI回调函数的第三个输入参数传入回调函数,以便于用户在回调函数中任意访问GUI数据。
handles结构体主要有两种用途。首先便是访问或修改GUI数据。由于handles保存有GUI对象数据,可在回调函数中,通过UI控件的tag值和句柄属性获取相关数据。其次是在回调函数间共享数据。用户可在handles中存储数据,在其他位置访问已经保存更新的数据。
1、访问或修改GUI数据
get(handles.edit1, 'String'); % 访问GUI数据
set(handles.pushbutton1, 'FontName', 'default'); % 修改GUI数据
2、共享数据
resoultion = handles.Resolution; % 获取数据
handles.Resolution = resolution; % 保存数据
guidata(hObject, handles); % 更新数据
3、C-MEX文件生成结构体
Matlab在矩阵运算上有这很强的优势,但涉及到多重循环时,效率非常低下,而C/C++对于循环由着很高效的处理。因此可通过混合编程的方式提高代码执行效率。通过编写mex文件,能够让matlab调用C/C++程序如同调用内置函数一般。
对于matlab和C/C++混合编程,matlab提供了很多API函数。由于文中主要涉及结构体使用,故在此仅列举与结构体相关的API函数,对于每个API函数的原型,可在MathWorks的Documentation主页中查到。
以下为结构体相关的API函数:
01. mxCreateStructArray() // 创建一个N维未赋值的结构体阵列
02. mxCreateStructMatrix() // 创建一个2维未赋值的结构体阵列
03. mxGetField() // 通过索引和字段名, 获得字段值
04. mxGetFieldByNumber() // 通过索引和字段位置,获取字段值
05. mxGetFieldNameByNumber() // 通过字段位置,获取字段名
06. mxGetFieldNumber() // 通过字段名,获取字段位置
07. mxGetNumberOfFields() // 获取结构体的字段数量
08. mxIsStruct() // 判断阵列是否为结构体阵列
09. mxSetField() // 通过索引值和字段名,设置字段值
10. mxSetFieldByNumber() // 通过索引值和字段位置,设置字段值
在此将以一个实例,讲述C-MEX文件生成复杂结构体。该文件主要用于将图2-(a)所示的txt文件内容转换成图2-(b)所示的结构。
该文件包含以下几个功能:
a.获取matlab传入的txt存放路径;
b.读取并解析txt文件,并用C/C++结构体存储解析到的数据;
c.生成matlab结构体
其具体功能实现如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mex.h"
#define MAX 3
#define SIZE 12
struct subfield{
int width;
int height;
};
struct resolution{
char field[SIZE];
struct subfield Value;
};
int getIndex(char *s, char c);
void parseTxt(char *path, struct resolution *res); // 解析txt文件
mxArray * createSubField(struct subfield *field); // 填写结构体字段
void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
{
struct resolution Resolution[MAX];
const char *fieldnames[MAX];
const int nfields = 3;
mwSize dim[2] = {1, 1};
mxArray *tmp;
char *path;
int i, *str_size;
/* 获取matlab传入的txt存放路径 */
str_size = (int *)mxGetDimensions(prhs[0]);
path = (char *)malloc(str_size[0]*str_size[1]+1);
mxGetString(prhs[0], path, str_size[0]*str_size[1]+1);
/* 解析txt文件 */
parseTxt(path, Resolution);
/* 获取字段名,并创建一个matlab结构体类型的返回值 */
for (i = 0; i < MAX; i++)
{
fieldnames[i] = Resolution[i].field;
}
plhs[0] = mxCreateStructArray(2, dim, nfields, fieldnames);
/* 装载数据 */
for (i = 0; i < MAX; i++)
{
tmp = createSubField(&(Resolution[i].Value));
mxSetFieldByNumber(plhs[0], 0, i, tmp);
}
}
int getIndex(char *s, char c)
{
int count = -1;
for (; *s != c && *s != '\0'; s++)
++count;
return count;
}
void parseTxt(char *path, struct resolution *res)
{
FILE *fp;
char tmpChar[20];
char *s1, *s2;
int count = -1;
int index;
fp = fopen(path, "rb");
while (!feof(fp))
{
fscanf(fp, "%s", tmpChar);
if (tmpChar[0] == '[')
{
count++;
memset(res[count].field, 0, SIZE);
index = getIndex(tmpChar, ']'); // 解析主字段
if (index != -1)
{
strncpy(res[count].field, tmpChar+1, index);
}
else
{
printf("Not found \"%c\"\n", ']');
}
}
else if (tmpChar[0] == 'w') // 解析 width
{
s1 = strtok(tmpChar, "=");
s2 = strtok(NULL, "=");
res[count].Value.width = atoi(s2);
}
else if (tmpChar[0] == 'h') // 解析 height
{
s1 = strtok(tmpChar, "=");
s2 = strtok(NULL, "=");
res[count].Value.height = atoi(s2);
}
}
fclose(fp);
}
mxArray * createSubField(struct subfield *field)
{
mxArray *ret, *val;
mwSize dim[2] = {1, 1};
const int nfields = 2;
const char *fieldnames[2] = {"width", "height"};
/* 创建结构体 */
ret = mxCreateStructArray(2, dim, nfields, fieldnames);
/* 填写 width */
val = mxCreateNumericMatrix(1, 1, mxINT16_CLASS, mxREAL);
memcpy(mxGetPr(val), &(field->width), sizeof(double));
mxSetFieldByNumber(ret, 0, 0, val);
/* 填写 height */
val = mxCreateNumericMatrix(1, 1, mxINT16_CLASS, mxREAL);
memcpy(mxGetPr(val), &(field->height), sizeof(double));
mxSetFieldByNumber(ret, 0, 1, val);
return ret;
}
参考文献:
[1] 罗华飞,2014. MATLAB GUI设计学习手记(第三版)[M]. 北京:北京航空航天大学出版社
[2] 李传军,2004. C语言与MATLAB接口——编程与实例[M]. 北京:北京邮电大学出版社
个人声明:
以上内容,纯属个人观点,不喜勿喷。博客中出现的代码仅供学习参考,不得有其他用途。若有大佬见此拙作,还望指点一二。有好的建议或者文中存在纰漏,欢迎留言,也可邮箱联系:yxyx_0212@163.com