不允许 dllimport 静态数据成员

c++dll导入导出宏定义,出现“无法定义dllimport 实体”和“不允许dllimport 静态数据成员的定义”的问题 问题如下: 建立dll项目后,在Api_Head.hpp头文件中,定义宏: #ifndef API_HEAD_HPP #define API_HEAD_HPP #ifdef API_DLL_COMPILATION #define API_IMPORT_EXPORT __declspec(dllexport) #else #define API_IMPORT_EXPORT __declspec(dllimport) #endif class API_IMPORT_EXPORT CServerCont 阅读详情
“CTest<T>::~CTest” : 不允许 dllimport 函数 的定义
  “CTest<T>::CTest” : 不允许 dllimport 函数 的定义



//代码如下

template<class T>
class __declspec(dllimport) CTest
{
public:
        CTest();
        ~CTest();
};

template<class T>
CTest<T>::CTest()
{
//
}

template<class T>
CTest<T>::~CTest()
{
//
}

当要使用一个类的时候必须要有其定义,有2种方式:
        1、引用其头文件,即#include "xxx.h"。这是传统的方式。
        2、使用导出类。

    什么是‘导出类’,很简单,使用__declspec(dllimport)定义的类即为导出类。例如:
    class __declspec(dllimport) CTest
    {
    }

    __declspec(dllimport)是MS特有的描述符,看名字就知道是用在DLL链接时用到的,DLL是WINDOWS的产物,就跨平台而言这 样的写法是不可取的。所有通用版本的STL都不会使用这个描述符,看到使用方式2的导出类定义自然就让人费解了。


    如果确实需要使用__declspec(dllimport),要注意VC规定:
    数据、静态数据成员和函数可以声明,但不能定义为 dllimport。

   说白了就是,声明和定义分别放在.h及.cpp文件中。即__declspec(dllimport)声明放在.h头文件中,实现放在.cpp文件中。 这样一处理,对于普通的函数、类就可以使用方式2所谓的‘导出类’了。然而对模板却不行。这里面还有涉及到编译器不能支持对模板的分离式编译的问题。

    首先说一下编译器的大致的编译原理。一个.cpp及其包括的所有.h经编译后叫做一个编译单元,即.obj文件,然后由连接器把所有的.obj连接生成一 个PE可执行.exe文件。举例main.obj要调用test.obj单元里面的test()函数,此时的main.obj并没有test()函数的代 码。连接器于是帮main.obj找到test.obj中test()函数的地址并链接到到main.obj中。平常大家玩反汇编的时候经常看到jmp xxx/call xxx就是连接器在做调配。

    再说一下模板。模板是需要‘具体化’的,编译器直到碰到使用这个模板代码的时候才会把模板编译成二进制代码。留意一下STL代码你会发现,所有模板代码全 都放在一个.h文件中,为什么不分开放在.cpp文件中,因为放在.cpp文件中即成为一个编译单元,一个单元就是一个PE结构,是实在的二进制代码文 件,但这个单元没有调用这个模板又哪来的编译单元,于是编译器只能罢工。有没有办法生成单元?有!在.cpp中变态地调用自己声明的模板。
    
    明白这个道理之后也就不难理解为什么有的时候可以编译通过链接的时候却报错了,链接器找不到另一个.obj的相应地址当然报错。



    现在来分析一下上面的模板代码为什么会出错,很简单:
    既然使用了__declspec(dllimport)声明,却又对CTest()及~CTest()进行定义,违反VC规则“数据、静态数据成员和函数可以声明,但不能定义为 dllimport。”

    解决:
    1、去掉__declspec(dllimport),除非你真的想生成DLL导出类,否则使之成为标准模板。
    2、去掉CTest()/~CTest()类外部定义,将定义迁至类内部。为什么不能将这2个函数的定义放在.cpp文件中上面已经有解释了。

 

上面说的不太完美:添加以下说明:

__declspec(dllexport)

声明一个导出函数,是说这个函数要从本DLL导出。我要给别人用。一般用于dll中 
省掉在DEF文件中手工定义导出哪些函数的一个方法。当然,如果你的DLL里全是C++的类的话,你无法在DEF里指定导出的函数,只能用__declspec(dllexport)导出类

__declspec(dllimport)

声明一个导入函数,是说这个函数是从别的DLL导入。我要用。一般用于使用某个dll的exe中 

不使用 __declspec(dllimport) 也能正确编译代码,但使用 __declspec(dllimport) 使编译器可以生成更好的代码。编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于 DLL 中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨 DLL 边界的函数调用中。但是,必须使用 __declspec(dllimport) 才能导入 DLL 中使用的变量。

使用举例:

 // File: SimpleDLLClass.h

#ifdef SIMPLEDLL_EXPORT
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT 
#endif

class DLL_EXPORT SimpleDLLClass
{
public:
 SimpleDLLClass();
 virtual ~SimpleDLLClass();

 virtual getValue() { return m_nValue;};
private:
 int m_nValue;
};
 

// File: SimpleDLLClass.cpp

#include "SimpleDLLClass.h"

SimpleDLLClass::SimpleDLLClass()
{
 m_nValue=0;
}

SimpleDLLClass::~SimpleDLLClass()
{
}

说明:
1. 在你的APP中include SimpleDLLClass.h时,如果你的APP的项目不定义SIMPLEDLL_EXPORT,则DLL_EXPORT不存在。此时APP仍可以正常运行。

// File: SimpleDLLClass.h
static int m_nValue;

// File: SimpleDLLClass.cpp
int SimpleDLLClass::m_nValue=0;
 

说明:
1. 如果你的APP的项目不定义SIMPLEDLL_EXPORT,则DLL_EXPORT不存在。此时APP无法LINK。原因是找不到m_nValue。(原因:静态变量m_nValue已被DLL导出,但SimpleDLLClass无法访问m_nValue)
Workaround:
#define DLL_EXPORT __declspec(dllimport)

Conclusion:
dllimport是为了更好的处理类中的静态成员变量(或者其他...)的,如果没有静态成员变量(或者其他...),那么这个__declspec(dllimport)无所谓.

/////////////////////////

在Windows DLL编程时,可使用__declspec(dllimport)关键字导入函数或者变量。

函数的导入
    当你需要使用DLL中的函数时,往往不需要显示地导入函数,编译器可自动完成。但如果你显示地导入函数,编译器会产生质量更好的代码。由于编译器确切地知道了一个函数是否在一个DLL中,它就可以产生更好的代码,不再需要间接的调用转接。
    Win32的PE格式(Portable Executable Format)把所有导入地址放在一个导入地址表中。下面用一个具体实例说明使用__declspec(dllimport)导入函数和不使用的区别:
    假设func是一个DLL中的函数,现在在要生成的.exe的main函数中调用func函数,并且不显示地导入func函数(即没有:__declspec(dllimport)),代码示例如下:
    int main()
    {
        func();
    }
编译器将产生类似这样的调用代码:
    call func
然后,链接器把该调用翻译为类似这样的代码:
    call 0x40000001       ; ox40000001是"func"的地址
并且,链接器将产生一个Thunk,形如:
    0x40000001: jmp DWORD PTR __imp_func
这里的imp_func是func函数在.exe的导入地址表中的函数槽的地址。然后,加载器只需要在加载时更新.exe的导入地址表即可。
    而如果使用了__declspec(dllimport)显示地导入函数,那么链接器就不会产生Thunk(如果不被要求的话),而直接产生一个间接调用。因此,下面的代码:
    __declspec(dllimport) void func1(void);
   void main(void) 
    {
        func1();
    }
将调用如下调用指令:
    call DWORD PTR __imp_func1
    因此,显示地导入函数能有效减少目标代码(因为不产生Thunk)。另外,在DLL中使用DLL外的函数也可以这样做,从而提高空间和时间效率。
变量的导入
    与函数不同的是,在使用DLL中的变量时,需要显示地导入变量。使用__declspec(dllimport)关键字导入变量。若在DLL中使 用.def导出变量,则应使用DATA修饰变量,而不是使用已经被遗弃的CONSTANT。因为CONSTANT可能需要使用指针间接访问变量,不确定什 么时候会出问题。
//////////////

我相信写WIN32程序的人,做过DLL,都会很清楚__declspec(dllexport)的作用,它就是为了省掉在DEF文件中手工定义导 出哪些 函数的一个方法。当然,如果你的DLL里全是C++的类的话,你无法在DEF里指定导出的函数,只能用__declspec(dllexport)导出 类。但是,MSDN文档里面,对于__declspec(dllimport)的说明让人感觉有点奇怪,先来看看MSDN里面是怎么说的: 
不使 用 __declspec(dllimport) 也能正确编译代码,但使用 __declspec(dllimport) 使编译器可以生成更好的代码。编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于 DLL 中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨 DLL 边界的函数调用中。但是,必须使用 __declspec(dllimport) 才能导入 DLL 中使用的变量。

初看起来,这段话前面的意思是,不用它也可以正常使用DLL的导出库,但最后一句话又说,必须使用 __declspec(dllimport) 才能导入 DLL 中使用的变量这个是什么意思??

那我就来试验一下,假定,你在DLL里只导出一个简单的类,注意,我假定你已经在项目属性中定义了 SIMPLEDLL_EXPORT
SimpleDLLClass.h

#ifdef SIMPLEDLL_EXPORT#define DLL_EXPORT __declspec(dllexport)#else#define DLL_EXPORT#endifclass DLL_EXPORT SimpleDLLClass{public: SimpleDLLClass(); virtual ~SimpleDLLClass(); virtual getValue() { return m_nValue;};private: int m_nValue;};SimpleDLLClass.cpp

#include "SimpleDLLClass.h"SimpleDLLClass::SimpleDLLClass() { m_nValue=0;}SimpleDLLClass::~SimpleDLLClass(){}然后你再使用这个DLL类,在你的APP中 include SimpleDLLClass.h时,你的APP的项目不用定义 SIMPLEDLL_EXPORT 所以,DLL_EXPORT 就不会存在了,这个时候,你在APP中,不会遇到问题。这正好对应MSDN上说的__declspec(dllimport)定义与否都可以正常使用。但 我们也没有遇到变量不能正常使用呀。 那好,我们改一下SimpleDLLClass,把它的m_nValue改成static,然后在cpp文件中加一行

int SimpleDLLClass::m_nValue=0;如果你不知道为什么要加这一行,那就回去看看C++的基础。 改完之后,再去LINK一下,你的APP,看结果如何, 结果是LINK告诉你找不到这个m_nValue。明明已经定义了,为什么又没有了?? 肯定是因为我把m_nValue定义为static的原因。但如果我一定要使用Singleton的Design Pattern的话,那这个类肯定是要有一个静态成员,每次LINK都没有,那不是完了? 如果你有Platform SDK,用里面的Depend程序看一下,DLL中又的确是有这个m_nValue导出的呀。
再回去看看我引用MSDN的那段话的最后一句。 那我们再改一下SimpleDLLClass.h,把那段改成下面的样子:

#ifdef SIMPLEDLL_EXPORT#define DLL_EXPORT __declspec(dllexport)#else#define DLL_EXPORT __declspec(dllimport)#endif再LINK,一切正常。原来dllimport是为了更好的处理类中的静态成员变量的,如果没有 静态成员变量,那么这个__declspec(dllimport)无所谓。

原文出处:http://www.cnblogs.com/kanego/archive/2012/02/02/2336220.html


c++静态成员变量成员函数 思考:每个变量,拥有属性。有没有一些属性,归所有对象拥有? 4.1静态成员变量 1)定义静态成员变量 关键字 static 可以用于说明一个类的成员, 静态成员提供了一个同类对象的共享机制  把一个类的成员说明为 static 时,这个类无论有多少个对象被创建,这些对象共享这个 static 成员静态成员局部于类,它不是对象成员 例如: #include using namespace std; class counter { static int num ; //声明与定义静态数据成员 阅读详情

相关推荐

嵌入式调光控制库:轻量级软启/渐变/记忆逻辑实现

调光控制是智能照明系统的核心基础功能,涉及亮度调节、人机交互与电气安全多重需求。其底层原理依赖于对相位角或PWM占空比的精确时序控制,并需融合软启动、渐变过渡、状态记忆等工程化逻辑。这类轻量级调光行为逻辑层,不直接操作硬件寄存器,而是以确定性、无动态内存、可配置的方式封装用户意图到目标亮度值(0–100%)的映射过程,显著提升产品鲁棒性与跨平台复用能力。广泛应用于TRIAC交流调光、LED直流PWM驱动及DALI/Matter等智能照明协议网关中,尤其适合资源受限的Cortex-M系列MCU和FreeRTO

weixin_28949937的博客 579

VS---不允许 dllimport 静态数据成员的定义

1、QT的Q_OBJECT包含静态数据定义: #define Q_OBJECT \ public: \ QT_WARNING_PUSH \ Q_OBJECT_NO_OVERRIDE_WARNING \ static const QMetaObject staticMetaObject; \ virtual const QMetaObject *metaObject() const; \ virtual void *qt_metacast(const char *)

路在脚下,Quick run! 5990

基于STM32与HRTIM的四开关Buck-Boost双向DC-DC电源设计实战(附源码、仿真与设计解析)

本文详细介绍了基于STM32F334的HRTIM高分辨率定时器实现四开关Buck-Boost双向DC-DC电源的设计实战。通过精准的PWM控制、双环PID算法和智能模式切换逻辑,解决了电压震荡与效率优化等关键问题,并提供了完整的源码、PSIM仿真及参数计算,为高性能电源设计提供了实用参考。

7z8x2c4v6b9的博客 299

qt报错:staticMetaObject”: 不允许 dllimport 静态数据成员 的定义

qt中使用动态库导出类,使用动态库的工程编译报错:xxx:staticMetaObject”: 不允许 dllimport 静态数据成员 的定义。

qq_43248127的博客 5653

跟着Cell学单细胞转录组分析(五):单细胞转录组marker基因鉴定及细胞群注释

书接上回(跟着Cell学单细胞转录组分析(四):单细胞转录组测序UMAP降维聚类)。完成数据降维和细胞聚类后,最主要的环节和工作就是确定各个细胞群,明确是什么类型的细胞,正群的细胞定群很关键,涉及到整个研究,所以这一步宁愿多费时间,也不要出错。当然,这也不是一蹴而就的,需要反复的确认。 要确定各个群是什么细胞,首先需要了解细胞群的marker基因,因为不同类型的细胞突出 表达的基因也是不同的。这里使用FindAllMarkers鉴定各个细胞群的高表达基因。 DefaultAssay(scedata)

qq_42090739的博客 1万+

图像处理(12)--图像各种噪声及消除方法

文章目录结构1.什么是图像噪声2. 图像噪声来源3. 噪声分类及其消除方法3.1 高斯噪声及其消除方式3.1.1 如何确定一种噪声是高斯噪声3.1.2 高斯滤波消除高斯噪声3.1.3 高斯函数的重要性质3.2 瑞利噪声及其消除方式3.3 伽马(爱尔兰)噪声及其消除方式3.4 指数分布噪声及其消除方式3.5 均匀噪声及其消除方式3.6 脉冲(椒盐)噪声及其消除方式 1.什么是图像噪声 图像噪声是指...

ShaneHolmes 11万+

不能定义声明dllimport_不允许 dllimport 静态数据成员

View Code“CTest::~CTest” : 不允许 dllimport 函数 的定义“CTest::CTest” : 不允许 dllimport 函数 的定义//代码如下templateclass __declspec(dllimport) CTest{public:CTest();~CTest();};templateCTest::CTest(){//}templateCTest::~...

weixin_39860975的博客 2644

AI驱动的网络安全运维:智能化时代的安全保障

本项目旨在使用Python和AI技术构建一个智能化的网络安全运维系统,能够实时监测网络流量,检测潜在的安全威胁,并自动采取应对措施,从而提升网络安全管理的效率和准确性。具体内容包括:环境配置与依赖安装数据采集与预处理机器学习模型构建与训练实时威胁检测与响应实际应用案例通过本文的介绍,我们展示了如何使用Python和AI技术构建一个智能化的网络安全运维系统。

Echo_Wish 1290

错误:在xx导出类中,不允许dllimport静态数据成员

错误: 在xx导出类中,不允许dllimport静态数据成员 原因: 在制作导出类时,没有在配置属性中添加导出类的宏 例如: 属性----->C/C++目录------->预处理器-------->添加对应宏

糯诺诺米团 995

融合双主干网络提升YOLOv8性能一种基于SOTA思想的目标检测改进

YOLOv8采用了单一的主干网络进行特征提取,通常是基于CSPDarknet作为骨干网络,在目标检测过程中通过不同的卷积层提取不同尺度的信息。虽然这种设计在大多数应用场景下表现出色,但在面对复杂背景、细节丰富的物体或小物体检测时,YOLOv8有时难以保持良好的精度。在本文中,我们提出了一种基于双主干网络的YOLOv8改进方案,通过结合先进的SOTA思想,全面提升了YOLOv8在目标检测任务中的表现。双主干网络架构。

博客 1154

【绝对要收藏-优秀论文范文】高项-度量绩效域

摘要:本文基于某水库数字孪生平台建设项目(2022.9-2023.5,645.97万元)的管理实践,从信息系统度量绩效域角度展开论述。项目构建了包含防洪调度等6大子系统的数字平台,实现洪水"四预"功能。重点分析了度量绩效域的五大要点:制定有效指标(如成本±8%偏差阈值)、多维数据采集、预警临界值设定、基于趋势的主动干预和持续改进机制。特别阐述了绩效问题的诊断方法,包括设备采购全周期成本分析、阶段性成本报告制度等。项目状态展示采用三维可视化看板,集成进度、成本、质量等多维度实时数据,最终实

xylllamm的博客 345

Log4qt直接pri引用出现 不允许 dllimport 静态数据成员 的定义

类似这种错误 “Log4Qt::Appender::staticMetaObject”: 不允许 dllimport 静态数据成员 的定义 只需在pro文件中定义 DEFINES += LOG4QT_LIBRARY 即便使用了.pri文件,也需要使用INCLUDEPATH

qq_36553572的博客 444

高通平台开发系列讲解(USB篇)MBIM协议详解

📢本文主要介绍高通平台USB网卡MBIM协议。

内核笔记 5440

VS不允许 dllimport 静态数据成员的定义

转载自:https://blog.youkuaiyun.com/wdh1314521/article/details/72910202   VS错误提示: 严重性 代码 说明 项目 文件行 禁止显示状态 错误 C2491 “SeaBreezeAPI::instance”: 不允许 dllimport 静态数据成员 的定义 VX700Pro E:\Oceanhood\Pro\seabreeze\SeaB...

huihuiwith的博客 7432

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

# 21-Qt编译dll库的时候,“不允许 dllimport 静态数据成员的定义”

在使用一个继承自QObject带有Q_OBJECT宏的导出类时,编译报错:不允许 dllimport 静态数据成员 的定义。 原因是自动生成的moc文件带有静态函数,无法导出。 在Qt中的解决办法是 去掉 Q_DECL_IMPORT ...

Robert Zhang 5055

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

C2491 “XXXXX::staticMetaObject”: 不允许 dllimport 静态数据成员 的定义

C2491 “XXXXX::staticMetaObject”: 不允许 dllimport 静态数据成员 的定义。我这个是Debug没编译过,Release编过了。比如你的工程名叫Project,那就改成PROJECT_LIB,然后重新编译。预处理定义中的XXX_LIB和自己的工程名称不一样,把它改成正确的就行。

qq_47830269的博客 986

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

qt 错误:不允许 dllimport 静态数据成员 的定义

标记的静态数据成员,Qt的编译器(如MSVC)可能会报错。在Qt中,如果你尝试在一个DLL中定义一个带有。将dllimport改成dllexport。

notfindjob的博客 1229

引用dll报错:error C2491-不允许 dllimport 静态数据成员 的定义

问题 创建一个QT的dll工程,生成lib、dll文件后,新建一个测试工程,将动态库的头文件、lib文件加入到该工程里,通过头文件引用dll的导出类. 编译测试工程时报错: 1>GeneratedFiles\Release\moc_TestDll.cpp(58): warning C4273: “TestDll::qt_static_metacall”: dll 链接不一致 1>...

无我 1万+

不允许 dllimport 静态数据成员 的定义_C++类和对象的定义

想用机器人赋能未来,少不了扎实的编程基本功,让我们跟着清华大学的C++语言程序课程一起过一遍C++的语法知识吧!C++语言特点——面向对象的程序设计对象是现实中的对象在程序中的模拟,类是同一类对象的抽象,对象是类的实例,设计类就是设计类型。围绕以下几个问题,此类型的“合法值”是什么?此类型应该有什么样的函数和操作符?新类型的对象该如何被创建和销毁?如何进行对象的初始化和赋值?对象作为函数...

weixin_39618176的博客 816

qt 不允许 dllimport 静态数据成员 的定义_C++类和对象的定义

想用机器人赋能未来,少不了扎实的编程基本功,让我们跟着清华大学的C++语言程序课程一起过一遍C++的语法知识吧!C++语言特点——面向对象的程序设计对象是现实中的对象在程序中的模拟,类是同一类对象的抽象,对象是类的实例,设计类就是设计类型。围绕以下几个问题,此类型的“合法值”是什么?此类型应该有什么样的函数和操作符?新类型的对象该如何被创建和销毁?如何进行对象的初始化和赋值?对象作为函数...

weixin_36221113的博客 1900

tips1:QT中staticMetaObject”: 不允许 dllimport 静态数据成员的定义解决方法

在使用一个继承自QObject带有Q_OBJECT宏的导出类时,编译报错:不允许 dllimport 静态数据成员 的定义。 原因是自动生成的moc文件带有静态函数,无法导出。 在Qt中的解决办法是 去掉 Q_DECL_IMPORT

mrpeterpan的博客 1746
上一篇: C++ debug和release版本的区别及调试技巧
下一篇: LNK4098: 默认库“MSVCRT”与其他库的使用冲突
ucasliming
博客等级 码龄16年 126粉丝 59原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值