接上篇文章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文件中的数据相关推荐

  1. php+easyui+上传文件,easyui 上传文件代码

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.IO ...

  2. 将文件流(InputStream)写入文件 将上传文件MultipartFile写到文件

    将文件流(InputStream)写入文件 方式一:不包裹Buffered(不使用缓冲) //将文件流(InputStream)写入文件 long size = 0; FileOutputStream ...

  3. Selenium+Python 下载文件与上传文件

    Selenium+Python 下载文件与上传文件 目录 下载文件功能 谷歌浏览器下载设置 切换iframe框架 鼠标悬浮元素定位 鼠标悬浮后出现的元素定位 上传文件 切换句柄 利用AutoIt进行桌 ...

  4. 文件在上传过程中发生异常服务器端,文件上传服务器端

    文件上传服务器端 内容精选 换一换 本节操作介绍本地Linux操作系统主机通过SCP向Linux云服务器传输文件的操作步骤.登录管理控制台,在ECS列表页面记录待上传文件的云服务器的弹性公网IP.上传 ...

  5. 文件传输服务器异常,文件在上传过程中发生异常 文件在上传过程前,安全组...

    文件在上传过程前,安全组件计算散列值失败是什么意思 需要把文件上传页面的网址添加到可信站点,具体操作步骤如下: 天黑路会滑,社会太复杂,还有什么东西比人心更可怕, 首先打开系统的internet选项卡 ...

  6. java删除文件的上一级_java中多级目录的删除

    1 多级目录的删除 public void Test(){ public static void main(String args[]){ File file =new File("文件名& ...

  7. 如何限制上传服务器的文件容量,如何通过配置php文件限制上传文件的大小

    在网站开发的过程中,为了确保能够充分利用服务器的空间,在开发上传功能时,必须对上传文件的大小进行控制.那么我们如何进行对上传文件的大小进行控制呢? 控制文件的大小可以从两个方面入手: 第一个是在PHP ...

  8. jsch 移动服务器上文件,jsch上传文件到服务器

    需求就是上传文件到服务器,服务器的存储地址由程序决定然后可以自动创建. 使用第三方:jsch JSch 是SSH2的一个纯Java实现.它允许你连接到一个sshd 服务器,使用端口转发,X11转发,文 ...

  9. php文件多上传文件,php文件上传(多文件上传)

    http://www.cnblogs.com/itcx/p/4209034.html upload.php class File_upload{ public $upload_path='./uplo ...

  10. C/C++下载文件_上传文件

    下载文件 service /************************************************************************* > File Na ...

最新文章

  1. OpenvSwitch — 操作实践
  2. include_fns.php_一步一步教你用PHP+MySql筹建网站 No.3 管理页面_mysql
  3. .NET Nancy 详解(三) Respone 和 ViewEngine
  4. 【POJ - 2762】Going from u to v or from v to u?(Tarjan缩点,树形dp 或 拓扑排序,欧拉图相关)
  5. Spring+springmvc+hibernate+redis整合配置文件
  6. IT必须掌握的面试大全技巧教你怎么回答
  7. 电子相册系统(七)查看原图
  8. 什么时候用到id和class?
  9. WMI 查询分析工具更新
  10. springboot毕业实习信息管理系统的设计与实现
  11. POS58打印机的操作
  12. 2021.11.27月赛题解
  13. 【校招笔试】网易校招网络笔试题,菜的抠脚,蠢的流泪
  14. 《2040大预言:高科技引擎与社会新秩序》——第2章 数字化概览2.1 一生中永不停息的视频日记...
  15. 研究生自救-写论文篇
  16. 通过ADO连接各种数据库的字符串
  17. 导购提成怎么算_导购提成应该怎么算?
  18. 免费的内网穿透(钉钉)
  19. Java学习总结2---Java集合类
  20. BEIT: BERT Pre-Training of Image Transformers论文解读

热门文章

  1. 南海有macbook吗?
  2. [转]Display PDF within web browser using MVC3
  3. OPEN ERP相关财务的基本概念
  4. Foursquare开源Rogue和Full-Loaded两款开发工具
  5. python中的list和array的区别及相互转化
  6. synchronized与Lock的区别与使用
  7. 原生 js 上传图片
  8. Linux操作oracle——关闭、停止、重启
  9. Java中谈尾递归--尾递归和垃圾回收的比较
  10. mybatis基础,mybatis配置文件核心组件typeHandler元素