打算看看Qt的源码了,毕竟也好几次被问到Qt的问题,现在想看看Qt里面的原理。查了一下说是从最初的版本看比较容易懂。在官网找了找,最低的版本都是1.4.2 了,但是更新时间确实2019年?还在更新不成?具体也不是很懂,咱也不知道去哪儿问,只能先把坑挖这儿有空了再填……
然后我在百度脑图上写了一下目录结构,如果想起了更新的话,应该会更新的……
html目录更像是文档,doc有点看不懂。重点还是src。我的目标是这样的,当看不懂src源码的时候,我再去看文档。主要Qt文档向来是只有用法,没有实现。所以还是得自己看源代码……
然后我发现src/moc
文件夹有点意思,知道qt会将signals
和Q_OBJECT
这些宏处理一下。处理的指令就是moc,而ui文件则是使用uic预处理。很好奇它怎么做到的。看看目录
.l .t 和.y文件
就是啥格式啊……
点击进去vscode让我找找插件,然后就出现了谜底:
这时候我们应该怎么样?诶,对了,大呼VSCODE天下第一!?
继续利用我们的互联网思维,google一下YACC,来到一个神奇的网站,当然不是58同城,而是很NB的IBM网站
看这意思,就是专门处理c语言文件的 语言,然后会形成新的文件。想了想在Qt里面可不是有中间的moc_xx.cc
的文件嘛。
看看这个moc.y
文件
obj_member_area: qt_access_specifier { BEGIN QT_DEF; }
slot_area
| SIGNALS { BEGIN QT_DEF; }
':' opt_signal_declarations
| Q_OBJECT { if ( tmpAccessPerm )
moc_warn("Q_OBJECT is not in the private"
" section of the class.\n"
"Q_OBJECT is a macro that resets"
" access permission to \"private\".");
Q_OBJECTdetected = TRUE; }
然后就看到一个神奇的函数
void generateClass() // generate C++ source code for a class
{
static int gen_count = 0;
char *hdr1 = "/****************************************************************************\n"
"** %s meta object code from reading C++ file '%s'\n**\n";
char *hdr2 = "** Created: %s\n"
"** by: The Qt Meta Object Compiler ($Revision: 2.25.2.11 $)\n**\n";
char *hdr3 = "** WARNING! All changes made in this file will be lost!\n";
char *hdr4 = "*****************************************************************************/\n\n";
int i;
if ( skipClass ) // don't generate for class
return;
if ( !Q_OBJECTdetected ) {
if ( signals.count() == 0 && slots.count() == 0 )
return;
generatedCode = TRUE;
if ( displayWarnings )
moc_err("The declaration of the class \"%s\" contains slots "
"and/or signals\n\t but no Q_OBJECT macro!", className.data());
} else {
if ( superclassName.isEmpty() )
moc_err("The declaration of the class \"%s\" contains the\n"
"\tQ_OBJECT macro but does not inherit from any class!\n"
"\tInherit from QObject or one of its descendants"
" or remove Q_OBJECT. ", className.data() );
}
if ( templateClass ) { // don't generate for class
moc_err( "Sorry, Qt does not support templates that contain\n"
"signals, slots or Q_OBJECT. This will be supported soon." );
return;
}
generatedCode = TRUE;
if ( gen_count++ == 0 ) { // first class to be generated
QDateTime dt = QDateTime::currentDateTime();
QString dstr = dt.toString();
QString fn = fileName;
i = fileName.length()-1;
while ( i>0 && fileName[i-1] != '/' && fileName[i-1] != '\\' )
i--; // skip path
if ( i >= 0 )
fn = &fileName[i];
fprintf( out, hdr1, (const char*)className, (const char*)fn );
fprintf( out, hdr2, (const char*)dstr );
fprintf( out, hdr3 );
fprintf( out, hdr4 );
fprintf( out, "#if !defined(Q_MOC_OUTPUT_REVISION)\n" );
fprintf( out, "#define Q_MOC_OUTPUT_REVISION %d\n", formatRevision );
fprintf( out, "#elif Q_MOC_OUTPUT_REVISION != %d\n", formatRevision );
fprintf( out, "#error \"Moc format conflict - "
"please regenerate all moc files\"\n" );
fprintf( out, "#endif\n\n" );
if ( !noInclude )
fprintf( out, "#include \"%s\"\n", (const char*)includeFile );
fprintf( out, "#include <%sqmetaobject.h>\n", (const char*)qtPath );
fprintf( out, "\n\n" );
} else {
fprintf( out, "\n\n" );
}
//
// Generate virtual function className()
//
fprintf( out, "const char *%s::className() const\n{\n ",
(const char*)className );
fprintf( out, "return \"%s\";\n}\n\n", (const char*)className );
//
// Generate static metaObj variable
//
fprintf( out, "QMetaObject *%s::metaObj = 0;\n\n", (const char*)className);
//
// Generate static meta-object constructor-object (we don't rely on
// it, except for QBuilder).
//
fprintf( out, "\n#if QT_VERSION >= 200\n" );
fprintf( out, "static QMetaObjectInit init_%s(&%s::staticMetaObject);\n\n",
(const char*)className, (const char*)className );
fprintf( out, "#endif\n\n" );
//
// Generate initMetaObject member function
//
fprintf( out, "void %s::initMetaObject()\n{\n", (const char*)className );
fprintf( out, " if ( metaObj )\n\treturn;\n" );
fprintf( out, " if ( strcmp(%s::className(), \"%s\") != 0 )\n"
"\tbadSuperclassWarning(\"%s\",\"%s\");\n",
(const char*)superclassName, (const char*)superclassName,
(const char*)className, (const char*)superclassName );
fprintf( out, "\n#if QT_VERSION >= 200\n" );
fprintf( out, " staticMetaObject();\n");
fprintf( out, "}\n\n");
//
// Generate staticMetaObject member function
//
fprintf( out, "void %s::staticMetaObject()\n{\n", (const char*)className );
fprintf( out, " if ( metaObj )\n\treturn;\n" );
fprintf( out, " %s::staticMetaObject();\n", (const char*)superclassName );
fprintf( out, "#else\n\n" );
fprintf( out, " %s::initMetaObject();\n", (const char*)superclassName );
fprintf( out, "#endif\n\n" );
//
// Build slots array in staticMetaObject()
//
generateFuncs( &slots, "slot", Slot_Num );
//
// Build signals array in staticMetaObject()
//
generateFuncs( &signals, "signal", Signal_Num );
//
// Finally code to create and return meta object
//
fprintf( out, " metaObj = new QMetaObject( \"%s\", \"%s\",\n",
(const char*)className, (const char*)superclassName );
if ( slots.count() )
fprintf( out, "\tslot_tbl, %d,\n", slots.count() );
else
fprintf( out, "\t0, 0,\n" );
if ( signals.count() )
fprintf( out, "\tsignal_tbl, %d );\n", signals.count());
else
fprintf( out, "\t0, 0 );\n" );
fprintf( out, "}\n" );
//
// End of function initMetaObject()
//
//
// Generate internal signal functions
//
Function *f;
f = signals.first(); // make internal signal methods
static bool included_list_stuff = FALSE;
while ( f ) {
QString typstr = ""; // type string
QString valstr = ""; // value string
QString argstr = ""; // argument string (type+value)
char buf[12];
Argument *a = f->args->first();
QString typvec[32], valvec[32], argvec[32];
typvec[0] = "";
valvec[0] = "";
argvec[0] = "";
i = 0;
while ( a ) { // argument list
if ( !a->leftType.isEmpty() || !a->rightType.isEmpty() ) {
if ( i ) {
typstr += ",";
valstr += ", ";
argstr += ", ";
}
typstr += a->leftType;
typstr += a->rightType;
argstr += a->leftType;
argstr += " ";
sprintf( buf, "t%d", i );
valstr += buf;
argstr += buf;
argstr += a->rightType;
++i;
typvec[i] = typstr.copy();
valvec[i] = valstr.copy();
argvec[i] = argstr.copy();
}
a = f->args->next();
}
bool predef_call = FALSE;
if ( typstr.isEmpty() || typstr == "short" || typstr == "int" ||
typstr == "long" || typstr == "char*" || typstr == "const char*"){
predef_call = TRUE;
}
if ( !predef_call && !included_list_stuff ) {
// yes we need it, because otherwise QT_VERSION may not be defined
fprintf( out, "\n#include <%sqobjectdefs.h>\n", (const char*)qtPath );
fprintf( out, "#if QT_VERSION >= 141\n" );
fprintf( out, "/" "/ newer implementation\n" );
fprintf( out, "#include <%sqsignalslotimp.h>\n", (const char*)qtPath );
fprintf( out, "#else\n" );
fprintf( out, "/" "/ for late-model 1.x header files\n" );
fprintf( out, "#if !defined(Q_MOC_CONNECTIONLIST_DECLARED)\n" );
fprintf( out, "#define Q_MOC_CONNECTIONLIST_DECLARED\n" );
fprintf( out, "#include <%sqlist.h>\n", (const char*)qtPath );
fprintf( out, "Q_DECLARE(QListM,QConnection);\n" );
fprintf( out, "Q_DECLARE(QListIteratorM,QConnection);\n" );
fprintf( out, "#endif\n" );
fprintf( out, "#endif\n" );
included_list_stuff = TRUE;
}
fprintf( out, "\n/" /* c++ */ "/ SIGNAL %s\n", (const char*)f->name );
fprintf( out, "void %s::%s(", (const char*)className,
(const char*)f->name );
if ( argstr.isEmpty() )
fprintf( out, ")\n{\n" );
else
fprintf( out, " %s )\n{\n", (const char*)argstr );
if ( predef_call ) {
fprintf( out, " activate_signal( \"%s(%s)\"",
(const char*)f->name, (const char*)typstr );
if ( !valstr.isEmpty() )
fprintf( out, ", %s", (const char*)valstr );
fprintf( out, " );\n}\n" );
f = signals.next();
continue;
}
int nargs = f->args->count();
fprintf( out, " QConnectionList *clist = receivers(\"%s(%s)\");\n",
(const char*)f->name, (const char*)typstr );
fprintf( out, " if ( !clist || signalsBlocked() )\n\treturn;\n" );
if ( nargs ) {
for ( i=0; i<=nargs; i++ ) {
fprintf( out, " typedef void (QObject::*RT%d)(%s);\n",
i, (const char*)typvec[i] );
fprintf( out, " typedef RT%d *PRT%d;\n", i, i );
}
} else {
fprintf( out, " typedef void (QObject::*RT)(%s);\n",
(const char*)typstr);
fprintf( out, " typedef RT *PRT;\n" );
}
if ( nargs ) {
for ( i=0; i<=nargs; i++ )
fprintf( out, " RT%d r%d;\n", i, i );
} else {
fprintf( out, " RT r;\n" );
}
fprintf( out, " QConnectionListIt it(*clist);\n" );
fprintf( out, " QConnection *c;\n" );
fprintf( out, " QSenderObject *object;\n" );
fprintf( out, " while ( (c=it.current()) ) {\n" );
fprintf( out, "\t++it;\n" );
fprintf( out, "\tobject = (QSenderObject*)c->object();\n" );
fprintf( out, "\tobject->setSender( this );\n" );
if ( nargs ) {
fprintf( out, "\tswitch ( c->numArgs() ) {\n" );
for ( i=0; i<=nargs; i++ ) {
fprintf( out, "\t case %d:\n", i );
fprintf( out, "\t\tr%d = *((PRT%d)(c->member()));\n", i, i );
fprintf( out, "\t\t(object->*r%d)(%s);\n",
i, (const char*)valvec[i] );
fprintf( out, "\t\tbreak;\n" );
}
fprintf( out, "\t}\n" );
} else {
fprintf( out, "\tr = *((PRT)(c->member()));\n" );
fprintf( out, "\t(object->*r)(%s);\n", (const char*)valstr );
}
fprintf( out, " }\n}\n" );
f = signals.next();
}
}
但是呢,这种预处理的确是有点超越我的维度知识,所以现在就只是看一遍作数,并不深究。然后就是看到一个qgloab.h的文件,为什么注意到它呢?因为我对QString 揭开头文件套娃的时候,发现它是最后一层。然后就发现了它可以通过宏来判断平台,编译器!
更妙的是它判断bool值的办法:
意思是早起的bool 可能只是一个宏?还是说是否定义了某个类型,真的可以通过#if defined(type)
来判断?
顺手查了下#ifdef 和#if defined 的区别……
就一个括号的区别,连结尾都是#endif
那么也就从另一个方面证明了,那里的bool 就是一个宏,早起的C++也是厉害。毕竟我一个半路出家的,通过代码来考古还是挺有必要的。先写这么多吧,继续挖坑
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。