大家好,欢迎来到IT知识分享网。
一、两者的区别
1、MSVC
即Microsoft Visual C++ Compiler,即微软自己的编译器。
我们下载Windows下的OpenCV时,解压后里面有两个文件夹,一个是build,一个是source,build这个文件夹实际上是官方已经提前给我们编译好了的库,会带两个文件夹VC14,VC15(分别与Visual Studio的版本有对应关系),这两个文件夹下的库可以直接运行不需要编译将VS作为Qt的开发环境也是使用这个编译器的缘故,但是,使用的必须是msvc编译器,不能够跨平台。
2、MinGW
二、两者优缺点
1、MSVC的优缺点
优点:
qtcreator的debuger有功能缺陷,经常会出现变量无法查看的问题,棘手的bug还是需要在VS环境下进行调试。很多人的开发模式就是qtcreator写代码,VS下面做调试。
缺点:
不能跨平台
编码的问题,QT5的Qstring默认是UTF8格式,QT5极力推介把源码用UTF8格式存储。 但是MSVC只支持带BOM的UTF8格式,qmake不支持带BOM的UTF8格式,逼我只能用GBK么。这样的话,用qt5,每次都要Qstring::fromLocal8bit(“我是中国人”);况且就算BOM问题解决了,源代码是UTF8了。MSVC的执行编码也是GBK
2、MinGW的优缺点
优点:
能跨平台
缺点:
MinGW无法利用生成的dump文件在windbg或VS下面定位到出错的代码
Scene3D在MinGW64位Release和MinGW32位Debug模式下运行直接闪退,而64位Debug和32位Release却正常运行。
动态删除继承QuickItem的对象,有几率导致非法内存访问,可以定位到问题在Qt源码中Renderer中的一处
三、两者的区别
1、编译器:
2、标准库:
3、开发环境:
而 MSVC 可以依赖 dll 动态库以及 lib 静态库,这就让编译出的 exe 文件可以比较小
下面是库依赖上的区别:
1、库文件格式:
四、库引用方式
1、MSVC编译的库是xxx.dll和xxx.lib,MingW编译的库是libxxx.dll和libxxx.dll.a
其中lib文件和.a文件一般都是对dll的引导;或者是包含了所有的源码,作用和dll一样
2、Qt调用msvc的dll
INCLUDEPATH += C:/Users/Administrator/Desktop/new/CTK-master/build_msvc2017/CTK-build/Libs/PluginFramework INCLUDEPATH += C:/Users/Administrator/Desktop/new/CTK-master/build_msvc2017/CTK-build/Libs/Core LIBS += -LC:/Users/Administrator/Desktop/new/CTK-master/build_msvc2017/CTK-build/bin/Debug -lCTKCore -lCTKPluginFramework
INCLUDEPATH +是头文件路径
LIBS +是lib库路径,这个路径下需要同时有dll和lib文件
3、Qt调用mingw的dll
INCLUDEPATH += C:/Users/Administrator/Desktop/new/CTK-master/build_mingw64/CTK-build/Libs/PluginFramework INCLUDEPATH += C:/Users/Administrator/Desktop/new/CTK-master/build_mingw64/CTK-build/Libs/Core LIBS += -LC:/Users/Administrator/Desktop/new/CTK-master/build_mingw64/CTK-build/bin/ -llibCTKCore LIBS += -LC:/Users/Administrator/Desktop/new/CTK-master/build_mingw64/CTK-build/bin/ -llibCTKPluginFramework LIBS += C:/Users/Administrator/Desktop/new/CTK-master/build_mingw64/CTK-build/bin/libCTKCore.dll.a LIBS += C:/Users/Administrator/Desktop/new/CTK-master/build_mingw64/CTK-build/bin/libCTKPluginFramework.dll.a
五、最后的选择
到底选择哪个版本,MinGW 比较方便,配置易上手适合初学者,MSVC功能强大,适合进阶,但是具体项目上要根据依赖的第三方库选择版本。
如果你的第三方库是msvc的,能可能就必须msvc,如果第三方库是mingw的可能就必须mingw。
跨平台开发的话,用的库基本上一定是Linux能用的库,而Linux能用的库一定是在mingw下支持会比较好。(mingw甚至能 include unistd.h 之类的Linux专用头文件),那就优选mingw。
注意Qt版本:msvc和MinGW版本的区别。msvc使用的是vs的编译器,这个版本主要用于PC开发;MinGW版本使用MinGW编译器,主要用于跨平台开发。两个版本的Qt配置方式完全不同。因此在网上搜配置方法时候,要加上msvc或者MinGW这样的关键字一块搜索。网上大部分内容是关于MinGW版本的配置方法,我本地使用的是msvc版本。Msvc版本配置比较简单;MinGW版本需要下载cmake自行编译opencv。
六、Qt中的各种编译器
1.uic:UI编译器,将.ui文件转化为ui_*.h文件
2.rcc:资源编译器,将.qrc文件转换成qrc_*.h文件
3.moc:元对象编译器,将含有Q_OBJECT的头文件转换成标准.h文件
4.qmake : 把pro文件编译成makefile文件,然后可以调用make命令
5.MSVC:微软VC++编译器
6.MinGW:gcc编译器
七、使用QLibrary加载动态库
使用QLibrary可以在程序运行时加载动态链接库。一个QLibrary的实例作用于一个单一的共享库上。QLibrary提供了一种平台无关的方式访问库中的函数。可以在构建QLibrary的实例时将要加载的库文件传入,也可以在创建实例后使用setFileName()显式的设置要加载的文件名。当加载库文件时,QLibrary会搜索所有平台特定的库位置,除非传入的文件名具有绝对路径。
如果传入的文件名具有绝对路径,那么会首先尝试加载该目录。如果该文件找不到,QLibrary会使用不同的平台特定的文件前缀或后缀再次尝试,比如Unix和Mac平台的”lib”前缀,Unix平台的”.so”后缀,Mac平台的”.dylib”,Windows平台的”.dll”。如果文件名不是绝对路径,QLibrary会修改搜索顺序,首先尝试系统特定的前缀和后缀,紧接着是指定的文件路径。
所以,基于QLibrary对库文件的搜索机制,我们推荐在传入库文件时只传入该库文件的基名,不写前缀或后缀。这样一来,同一份代码可以在不同的操作系统上工作,并且该机制会保证进行最小次数的搜索。
该类中最重要的函数是load(),该函数动态的加载库文件,isLoaded()可以用来检查库文件是否成功加载,而resolve()函数则用来解析库中的符号地址,主要是函数地址。并且,resolve()函数在库文件未被加载时会隐式的尝试加载它。多个QLibrary实例可以可以访问同一个库文件。因为,库文件一旦被加载,就会驻留在内存中直到应用程序终止。当然,我们可以使用unload()函数来尝试卸载一个库文件,但是如果有其他的QLibrary实例正在引用同一个库文件,unload()会调用失败,并且该库文件会在所以实例都调用了unload()后才被卸载。
QLibrary库的典型用法是去解析一个库中的导出符号,并调用该符号表示的C函数。这被称为“显式链接”,而相对的“隐式链接”是在编译过程的链接阶段完成的。如下面的代码显示的那样,改代码先加载一个库,解析其中的”mysymbol”符号,并在成功的情况下,调用该函数。如果由于某种原因出错了,例如库文件不存在或该符号未被定义,那么相应的函数指针将被设为空,不会发生实际的调用:
QLibrary myLib("mylib"); typedef void (*MyPrototype)(); MyPrototype myFunction = (MyPrototype) myLib.resolve("mysymbol"); if (myFunction) myFunction();
但该符号必须被导出为C函数。也就是说,如果该库是由C++编译器编译的,那么该函数必须被包在extern “C”块中。并且在Windows平台上,还需要使用dllexport宏来修饰该函数。
出于方便,该类还提供了一个静态的resolve()函数,我们可以使用该函数来解析并调用一个库中的方法,而不需要先加载该库。如下代码所示:
typedef void (*MyPrototype)(); MyPrototype myFunction = (MyPrototype) QLibrary::resolve("mylib", "mysymbol"); if (myFunction) myFunction();
其实,除了静态的resolve()函数,该类还提供了一个静态的isLibrary()函数,该函数可以根据特定平台来判断一个文件是否是可被加载的库。其所使用的规则如下:
八、QT MinGW 怎样调用 VS的DLL库
例1:
#include "dialog.h" #include <QApplication> #include <QLibrary> typedef int (*func_Add)(int a, int b); //定义函数指针(一定要与要调用的库里面的参数类型及返回类型一致) typedef int (*func_Sub)(int a, int b); typedef int (*func_Mul)(int a, int b); int main(int argc, char *argv[]) { QApplication a(argc, argv); QLibrary mylib("testdll.dll");//testdll.dll的存放路径与.exe一致 if (mylib.load()) { //"?Add@Ctestdll@@QAEHHH@Z"等字符串其实就是动态库函数int Add(int a, int b)的变体,请使用微软工具DEPENDS.EXE查看得到(最重要的一步 从?开始的所有内容都要复制) func_Add f1 = (func_Add)mylib.resolve("?Add@Ctestdll@@QAEHHH@Z"); func_Sub f2 = (func_Sub)mylib.resolve("?Sub@Ctestdll@@QAEHHH@Z"); func_Mul f3 = (func_Mul)mylib.resolve("?Mul@Ctestdll@@QAEHHH@Z"); int rt = 0; if (f1 != NULL) { rt = f1(10, 12); } if (f2 != NULL) { rt = f2(10, 12); } if (f3 != NULL) { rt = f3(10, 12); } }`在这里插入代码片` (完美运行!!!) Dialog w; w.show(); return a.exec(); }
例2:
ZLGLIB.h
#ifndef _ZLBLIB_ #define _ZLBLIB_ #pragma once #include "ControlCAN.h" extern VCI_OpenDevice OpenDevice; extern VCI_CloseDevice CloseDevice; extern VCI_InitCAN InitCAN; extern VCI_ReadBoardInfo ReadBoardInfo; extern VCI_ReadErrInfo ReadErrInfo; extern VCI_ReadCANStatus ReadCANStatus; extern VCI_GetReference GetReference; extern VCI_SetReference SetReference; extern VCI_GetReceiveNum GetReceiveNum; extern VCI_ClearBuffer ClearBuffer; extern VCI_StartCAN StartCAN; extern VCI_ResetCAN ResetCAN; extern VCI_Transmit Transmit; extern VCI_Receive Receive; BOOL ZLGLIB(); #endif
ZLGLIB.cpp
// #include "stdafx.h" #include "ZLGLIB.h" #include <QLibrary> VCI_OpenDevice OpenDevice; VCI_CloseDevice CloseDevice; VCI_InitCAN InitCAN; VCI_ReadBoardInfo ReadBoardInfo; VCI_ReadErrInfo ReadErrInfo; VCI_ReadCANStatus ReadCANStatus; VCI_GetReference GetReference; VCI_SetReference SetReference; VCI_GetReceiveNum GetReceiveNum; VCI_ClearBuffer ClearBuffer; VCI_StartCAN StartCAN; VCI_ResetCAN ResetCAN; VCI_Transmit Transmit; VCI_Receive Receive; QLibrary lib("ControlCAN.dll"); BOOL ZLGLIB() { OpenDevice = NULL; CloseDevice = NULL; InitCAN = NULL; ReadBoardInfo = NULL; ReadErrInfo = NULL; ReadCANStatus = NULL; GetReference = NULL; SetReference = NULL; GetReceiveNum = NULL; ClearBuffer = NULL; StartCAN = NULL; ResetCAN = NULL; Transmit = NULL; Receive = NULL; if(!lib.load()) { return FALSE; } OpenDevice = (VCI_OpenDevice)lib.resolve("VCI_OpenDevice"); CloseDevice= (VCI_CloseDevice)lib.resolve("VCI_CloseDevice"); InitCAN= (VCI_InitCAN)lib.resolve("VCI_InitCAN"); ReadBoardInfo= (VCI_ReadBoardInfo)lib.resolve("VCI_ReadBoardInfo"); ReadErrInfo= (VCI_ReadErrInfo)lib.resolve("VCI_ReadErrInfo"); ReadCANStatus= (VCI_ReadCANStatus)lib.resolve("VCI_ReadCANStatus"); GetReference= (VCI_GetReference)lib.resolve("VCI_GetReference"); SetReference= (VCI_SetReference)lib.resolve("VCI_SetReference"); GetReceiveNum= (VCI_GetReceiveNum)lib.resolve("VCI_GetReceiveNum"); ClearBuffer= (VCI_ClearBuffer)lib.resolve("VCI_ClearBuffer"); StartCAN= (VCI_StartCAN)lib.resolve("VCI_StartCAN"); ResetCAN= (VCI_ResetCAN)lib.resolve("VCI_ResetCAN"); Transmit= (VCI_Transmit)lib.resolve("VCI_Transmit"); Receive= (VCI_Receive)lib.resolve("VCI_Receive"); if (OpenDevice == NULL || CloseDevice == NULL|| InitCAN == NULL || ReadBoardInfo == NULL || ReadErrInfo == NULL || ReadCANStatus == NULL || GetReference == NULL || SetReference == NULL || GetReceiveNum == NULL || ClearBuffer == NULL || StartCAN == NULL || ResetCAN == NULL || Transmit == NULL || Receive == NULL ) { return FALSE; } return TRUE; }
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/128920.html