2.MOC文件解读(上)——MOC文件中的数据
接上篇文章https://blog.csdn.net/Master_Cui/article/details/109007448
moc文件开始是个结构体
QT_BEGIN_MOC_NAMESPACE
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
struct qt_meta_stringdata_moctest_t {QByteArrayData data[7];char stringdata0[41];
};
里面有两个数组,其中QByteArrayData在qarraydata.h中,结构如下
struct Q_CORE_EXPORT QArrayData
{QtPrivate::RefCount ref;int size;uint alloc : 31;uint capacityReserved : 1;qptrdiff offset; // in bytes from beginning of headervoid *data(){Q_ASSERT(size == 0|| offset < 0 || size_t(offset) >= sizeof(QArrayData));return reinterpret_cast<char *>(this) + offset;}const void *data() const{Q_ASSERT(size == 0|| offset < 0 || size_t(offset) >= sizeof(QArrayData));return reinterpret_cast<const char *>(this) + offset;}//以下省略......
};
size是指针指向数据的大小,offset是数据指针和当前对象指针的距离(偏移量),如果数据大小不是0,data函数就根据偏移量offset和当前对象的地址返回当前数据的指针
接下来是这两部分QT_MOC_LITERAL和qt_meta_stringdata_moctest_t
#define QT_MOC_LITERAL(idx, ofs, len) \Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \qptrdiff(offsetof(qt_meta_stringdata_moctest_t, stringdata0) + ofs \- idx * sizeof(QByteArrayData)) \)
static const qt_meta_stringdata_moctest_t qt_meta_stringdata_moctest = {{
QT_MOC_LITERAL(0, 0, 7), // "moctest"
QT_MOC_LITERAL(1, 8, 5), // "sigf1"
QT_MOC_LITERAL(2, 14, 0), // ""
QT_MOC_LITERAL(3, 15, 5), // "sigf2"
QT_MOC_LITERAL(4, 21, 5), // "slotf"
QT_MOC_LITERAL(5, 27, 6), // "slotf2"
QT_MOC_LITERAL(6, 34, 6) // "slotf3"},"moctest\0sigf1\0\0sigf2\0slotf\0slotf2\0""slotf3"
};
先是一个复杂的宏QT_MOC_LITERAL,然后通过该宏初始化结构体qt_meta_stringdata_moctest_t,而结构体的第一个数组就是QByteArrayData,所以宏QT_MOC_LITERAL返回的一定是QByteArrayData数据
七个QT_MOC_LITERAL宏后面的一堆字符串对应结构体qt_meta_stringdata_moctest_t中的第二个数组,字符串的内容分别是类名,信号和槽
先看QT_MOC_LITERAL的实现,开始又是一个大宏Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET,但是最终的展开如下
#define Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset)
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET的展开如下
#define Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \{ Q_REFCOUNT_INITIALIZE_STATIC, size, 0, 0, offset } \
大括号里面的内容正好用来初始化QArrayData中的成员变量,Q_REFCOUNT_INITIALIZE_STATIC是-1,alloc和capacityReserved都是0
之后大宏里面是
(len, qptrdiff(offsetof(qt_meta_stringdata_moctest_t, stringdata0) + ofs - idx * sizeof(QByteArrayData)))
len对应size,后面的其实就是一个数qptrdiff就是int,offsetof用于求结构体中一个成员在该结构体中的偏移量,在stddef.h头文件中。qptrdiff(offsetof(qt_meta_stringdata_moctest_t, stringdata0) + ofs - idx * sizeof(QByteArrayData))对应offset,算出来这两个数据的值,然后初始化QByteArrayData数组
通过上面的一通计算,就能通过QByteArrayData中的data函数计算出下面字符串的地址
for (int i=0;i<7;++i) {cout<<(char *)(qt_meta_stringdata_moctest.data[i].data())<<endl;
}
接着,再看一下数组qt_meta_data_moctest
static const uint qt_meta_data_moctest[] = {// content:8, // revision 版本号,没啥用0, // classname 0, 0, // classinfo5, 14, // methods0, 0, // properties0, 0, // enums/sets0, 0, // constructors0, // flags2, // signalCount// signals: name, argc, parameters, tag, flags1, 1, 39, 2, 0x06 /* Public */,3, 2, 42, 2, 0x06 /* Public */,// slots: name, argc, parameters, tag, flags4, 1, 47, 2, 0x09 /* Protected */,5, 1, 50, 2, 0x09 /* Protected */,6, 1, 53, 2, 0x09 /* Protected */,// signals: parametersQMetaType::Void, QMetaType::Double, 2,QMetaType::Int, QMetaType::Char, QMetaType::Int, 2, 2,// slots: parametersQMetaType::Void, QMetaType::Double, 2,QMetaType::Int, QMetaType::Char, 2,QMetaType::Bool, QMetaType::Char, 2,0 // eod
};
下面拆解该数组
1.目录数据content
8, // revision 版本号,不用管0, // classname 类名在stringdata中的索引,总是0,qt_meta_stringdata_moctest.data[0].data()0, 0, // classinfo//不用管5, 14, // methods//信号槽的总数,3个槽函数,2个信号函数,从该数组中的第15个元素(qt_meta_data_moctest[14]])开始描述0, 0, // properties 属性数量和在该数组中的起始位置,这里为00, 0, // enums/sets //不用管0, 0, // constructors //不用管0, // flags //不用管2, // signalCount //信号个数2个
这些数据对应一个结构QMetaObjectPrivate
struct QMetaObjectPrivate
{// revision 7 is Qt 5.0 everything lower is not supported// revision 8 is Qt 5.12: It adds the enum name to QMetaEnumenum { OutputRevision = 8 }; // Used by moc, qmetaobjectbuilder and qdbusint revision;int className;int classInfoCount, classInfoData;int methodCount, methodData;int propertyCount, propertyData;int enumeratorCount, enumeratorData;int constructorCount, constructorData;int flags;int signalCount;//以下省略......
};
2.信号槽参数数据
// signals: name, argc, parameters, tag, flags1, 1, 39, 2, 0x06 /* Public */,3, 2, 42, 2, 0x06 /* Public */,// slots: name, argc, parameters, tag, flags4, 1, 47, 2, 0x09 /* Protected */,5, 1, 50, 2, 0x09 /* Protected */,6, 1, 53, 2, 0x09 /* Protected */,
第一列数据表示信号槽的索引,以 1, 1, 39, 2, 0x06 /* Public */为例,第一个1和QT_MOC_LITERAL(1, 8, 5)中的表示的都是同一个意思
第二列数据表示信号槽函数的参数个数,以以 1, 1, 39, 2, 0x06 /* Public */为例,第二个1表示信号函数sigf1有一个形参,参数类型是double
第三列数据表示参数数据的描述是从数组qt_meta_data_moctest[39]开始描述的,比如这里面的39,开头14个content数据,然后又有25个数字,到第11行的 QMetaType::Void时,正好是qt_meta_data_moctest[39]
第四列数据表示tag信息,是 qt_meta_stringdata_Widget.data[2].data() 指向的空字符串。好像一般的MOC文件的tag标志都是2,没啥特殊意义
第五列数据表示信号槽函数标志位,在qmetaobject_p.h 里声明,声明如下
enum MethodFlags {AccessPrivate = 0x00,AccessProtected = 0x01,AccessPublic = 0x02,AccessMask = 0x03, //maskMethodMethod = 0x00,MethodSignal = 0x04,MethodSlot = 0x08,MethodConstructor = 0x0c,MethodTypeMask = 0x0c,MethodCompatibility = 0x10,MethodCloned = 0x20,MethodScriptable = 0x40,MethodRevisioned = 0x80
};
将上述枚举按位或,就能得到第五列数据以 1, 1, 39, 2, 0x06 /* Public */为例,0x06=0x02 | 0x04,表示public signal
// signals: parametersQMetaType::Void, QMetaType::Double, 2,QMetaType::Int, QMetaType::Char, QMetaType::Int, 2, 2,// slots: parametersQMetaType::Void, QMetaType::Double, 2,QMetaType::Int, QMetaType::Char, 2,QMetaType::Bool, QMetaType::Char, 2,
第10行到第17行表示信号槽函数的返回值和形参类型,以QMetaType::Int, QMetaType::Char, QMetaType::Int, 2, 2,为例,QMetaType::Int是信号的返回值,QMetaType::Char, QMetaType::Int是信号函数的形参
最后一块数据部分就是moctest::staticMetaObject
QT_INIT_METAOBJECT const QMetaObject moctest::staticMetaObject = { {QMetaObject::SuperData::link<QObject::staticMetaObject>(),qt_meta_stringdata_moctest.data,qt_meta_data_moctest,qt_static_metacall,nullptr,nullptr
} };
moctest::staticMetaObject的类型是QMetaObject,QMetaObject的结构如下(位于qobjectdefs.h中)
struct Q_CORE_EXPORT QMetaObject
{struct { // private dataSuperData superdata;const QByteArrayData *stringdata;const uint *data;typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **);StaticMetacallFunction static_metacall;const SuperData *relatedMetaObjects;void *extradata; //reserved for future use} d;
};
里面的数据d的格式和moctest::staticMetaObject的初始值对应
SuperData superdata的初始值为QMetaObject::SuperData::link<QObject::staticMetaObject>(),表示基类的元对象数据
stringdata的初始值为qt_meta_stringdata_moctest.data,指向的是qt_meta_stringdata_moctest_t中的data数组(也就是那八个字符串的指针)
data的初始值为qt_meta_data_moctest,该指针指向数组qt_meta_data_moctest
typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **);声明了一个函数指针,指针的类型是void (*)(QObject *, QMetaObject::Call, int, void **);
接着,通过函数指针的类型定义了一个函数指针static_metacall,static_metacall的初始值为qt_static_metacall
最后两个数据relatedMetaObjects和extradata分别表示相关元对象指针和额外数据,一般都都指向空,不是很重要
参考
Qt5.14源码
https://qtguide.ustclug.org/
Inside Qt Series (全集)
欢迎大家评论交流,作者水平有限,如有错误,欢迎指出
2.MOC文件解读(上)——MOC文件中的数据相关推荐
- php+easyui+上传文件,easyui 上传文件代码
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.IO ...
- 将文件流(InputStream)写入文件 将上传文件MultipartFile写到文件
将文件流(InputStream)写入文件 方式一:不包裹Buffered(不使用缓冲) //将文件流(InputStream)写入文件 long size = 0; FileOutputStream ...
- Selenium+Python 下载文件与上传文件
Selenium+Python 下载文件与上传文件 目录 下载文件功能 谷歌浏览器下载设置 切换iframe框架 鼠标悬浮元素定位 鼠标悬浮后出现的元素定位 上传文件 切换句柄 利用AutoIt进行桌 ...
- 文件在上传过程中发生异常服务器端,文件上传服务器端
文件上传服务器端 内容精选 换一换 本节操作介绍本地Linux操作系统主机通过SCP向Linux云服务器传输文件的操作步骤.登录管理控制台,在ECS列表页面记录待上传文件的云服务器的弹性公网IP.上传 ...
- 文件传输服务器异常,文件在上传过程中发生异常 文件在上传过程前,安全组...
文件在上传过程前,安全组件计算散列值失败是什么意思 需要把文件上传页面的网址添加到可信站点,具体操作步骤如下: 天黑路会滑,社会太复杂,还有什么东西比人心更可怕, 首先打开系统的internet选项卡 ...
- java删除文件的上一级_java中多级目录的删除
1 多级目录的删除 public void Test(){ public static void main(String args[]){ File file =new File("文件名& ...
- 如何限制上传服务器的文件容量,如何通过配置php文件限制上传文件的大小
在网站开发的过程中,为了确保能够充分利用服务器的空间,在开发上传功能时,必须对上传文件的大小进行控制.那么我们如何进行对上传文件的大小进行控制呢? 控制文件的大小可以从两个方面入手: 第一个是在PHP ...
- jsch 移动服务器上文件,jsch上传文件到服务器
需求就是上传文件到服务器,服务器的存储地址由程序决定然后可以自动创建. 使用第三方:jsch JSch 是SSH2的一个纯Java实现.它允许你连接到一个sshd 服务器,使用端口转发,X11转发,文 ...
- php文件多上传文件,php文件上传(多文件上传)
http://www.cnblogs.com/itcx/p/4209034.html upload.php class File_upload{ public $upload_path='./uplo ...
- C/C++下载文件_上传文件
下载文件 service /************************************************************************* > File Na ...
最新文章
- OpenvSwitch — 操作实践
- include_fns.php_一步一步教你用PHP+MySql筹建网站 No.3 管理页面_mysql
- .NET Nancy 详解(三) Respone 和 ViewEngine
- 【POJ - 2762】Going from u to v or from v to u?(Tarjan缩点,树形dp 或 拓扑排序,欧拉图相关)
- Spring+springmvc+hibernate+redis整合配置文件
- IT必须掌握的面试大全技巧教你怎么回答
- 电子相册系统(七)查看原图
- 什么时候用到id和class?
- WMI 查询分析工具更新
- springboot毕业实习信息管理系统的设计与实现
- POS58打印机的操作
- 2021.11.27月赛题解
- 【校招笔试】网易校招网络笔试题,菜的抠脚,蠢的流泪
- 《2040大预言:高科技引擎与社会新秩序》——第2章 数字化概览2.1 一生中永不停息的视频日记...
- 研究生自救-写论文篇
- 通过ADO连接各种数据库的字符串
- 导购提成怎么算_导购提成应该怎么算?
- 免费的内网穿透(钉钉)
- Java学习总结2---Java集合类
- BEIT: BERT Pre-Training of Image Transformers论文解读