declspec关键字详细用法

合集下载

MFC在WINMAIN之前做的手脚

MFC在WINMAIN之前做的手脚

上个月有人问过MFC中一些全局变量的问题,最近工作中也是用到了MFC,所以追踪了下MFC的一些源码,查看了网上一些资料,在此作个小记录。

首先来认识几个类view plaincopy to clipboardprint?1.class CNoTrackObject//状态基类2.{3.public:4.void* PASCAL operator new(size_t nSize);5.void PASCAL operator delete(void*);6.#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)7.void* PASCAL operator new(size_t nSize, LPCSTR, int);8.#endif9.virtual ~CNoTrackObject() { }10.};这个类就重载了operator new和operator delete操作符。

class AFX_MODULE_STATE : public CNoTrackObject列举下它的几个眼熟的成员变量:CWinApp* m_pCurrentWinApp;HINSTANCE m_hCurrentInstanceHandle;HINSTANCE m_hCurrentResourceHandle;LPCTSTR m_lpszCurrentAppName;BYTE m_bDLL; // TRUE if module is a DLL, FALSE if it is an EXEBYTE m_bSystem; // TRUE if module is a "system" module, FALSE if not 。

从这个类的部分注释和成员名称类型可以隐约判断出来实例指针,实例句柄、资源句柄、应用程序名称、是否为DLL模块、是否为系统模块等等。

c++ 导出函数 非导出函数

c++ 导出函数 非导出函数

c++ 导出函数非导出函数C++是一种面向对象编程语言,同时也可以用作系统级编程语言。

在C++中,函数分为导出函数和非导出函数两种。

导出函数是可以在不同的编译单元之间进行调用的函数。

也就是说,在不同的.cpp文件中定义的函数,需要在链接时将这些函数进行链接,然后才能进行正常调用。

在C++中,导出函数需要在函数定义之前加上关键字“__declspec(dllexport)”进行声明。

下面是一个例子:```c++__declspec(dllexport) void MyExportFunction(){// 函数代码}```在使用导出函数的程序中,需要在头文件中进行声明,然后在需要进行调用的地方进行引用。

下面是一个例子:```c++// Header.h__declspec(dllimport) void MyExportFunction();#include "Header.h"{MyExportFunction();return 0;}```与导出函数相反,非导出函数是无法在不同的编译单元之间进行调用的函数。

也就是说,在不同的.cpp文件中定义的非导出函数,只能在本文件中进行调用。

在C++中,非导出函数不需要进行特殊的定义或声明。

下面是一个例子:```c++// MyFunction.cppvoid MyNonExportFunction(){// 函数代码}void MyAnotherFunction(){// 调用MyNonExportFunction函数MyNonExportFunction();}{MyAnotherFunction();return 0;}```需要注意的是,在非导出函数中使用全局变量或静态变量时,这些变量的作用域仍然是全局的,即这些变量可以被本文件中的其他函数使用。

在C++中,导出函数和非导出函数分别用于在不同的编译单元中进行调用和限制函数的作用域。

C++__declspec关键字详细用法

C++__declspec关键字详细用法

__declspec关键字详细用法2010-03-04 15:04__declspec用于指定所给定类型的实例的与Microsoft相关的存储方式。

其它的有关存储方式的修饰符如static与extern等是C 而__declspec是一种扩展属性的定义。

扩展属性语法简化并标准化了C和C++语言关于Microsoft的扩展。

用法:__declspec ( extended-decl-modifier )extended-decl-modifier参数如下,可同时出现,中间有空格隔开:align (C++)allocateappdomaindeprecated (C++)dllimportdllexportjitintrinsicnaked (C++)noaliasnoinlinenoreturnnothrow (C++)novtableprocessproperty(C++)restrictselectanythreaduuid(C++)1.__declspec关键字应该出现在简单声明的前面。

对于出现在*或&后面或者变量声明中标识符的前面的__declspec,编译器将忽2.要注意区分__declspec是修饰类型还是修饰变量:__declspec(align(8)) struct Str b;修饰的是变量b。

其它地方定义的struct Str类型的变量将不受__declspec(align(8))影响。

__declspec(align(8)) struct Str {};修饰的是struct Str类型。

所有该类型的变量都受__declspec(align(8))影响。

align:格式:__declspec(align(n)) declarator其中,n是对齐参数,其有效值是2的整数次幂(从1到8192字节),如2,4,8,16,32或64。

参数declarator是要设置对1.使用__declspec(align(n))来精确控制用户自定义数据的对齐方式。

_declspec用法

_declspec用法

__declspec用于指定所给定类型的实例的与Microsoft相关的存储方式。

其它的有关存储方式的修饰符如static与extern等是C和 C++语言的ANSI规范,而__declspec是一种扩展属性的定义。

扩展属性语法简化并标准化了C和C++语言关于Microsoft的扩展。

用法:__declspec ( extended-decl-modifier )extended-decl-modifier参数如下,可同时出现,中间有空格隔开:align (C++)allocateappdomaindeprecated (C++)dllimportdllexportjitintrinsicnaked (C++)noaliasnoinlinenoreturnnothrow (C++)novtableprocessproperty(C++)restrictselectanythreaduuid(C++)1.__declspec关键字应该出现在简单声明的前面。

对于出现在*或&后面或者变量声明中标识符的前面的 __declspec,编译器将忽略并且不给出警告。

2.要注意区分__declspec是修饰类型还是修饰变量:__declspec(align(8)) struct Str b;修饰的是变量b。

其它地方定义的struct Str类型的变量将不受__declspec(align(8))影响。

__declspec(align(8)) struct Str {};修饰的是struct Str类型。

所有该类型的变量都受__declspec(align(8))影响。

align:格式:__declspec(align(n)) declarator其中,n是对齐参数,其有效值是的整数次幂(从到字节),如,,,,或。

参数declarator 是要设置对齐方式的数据。

1.使用__declspec(align(n))来精确控制用户自定义数据的对齐方式。

调用约定(Calling convention)详解(__stdcall,__cdecl,__fastcall)

调用约定(Calling convention)详解(__stdcall,__cdecl,__fastcall)

调用约定(Calling convention)详解(__stdcall,__cdecl,__fastcall)分类:c/c++/vc 2010-03-12 10:21 233人阅读评论(1) 收藏举报#define CALLBACK __stdcall#define WINAPI __stdcall#define WINAPIV __cdecl#define APIENTRY WINAPI#define APIPRIVATE __stdcall#define PASCAL __stdcall调用约定(Calling convention):决定函数参数传送时入栈和出栈的顺序,由调用者还是被调用者把参薯弹出栈,以及编译器用来识别函数名字的修饰约定。

函数调用约定有多种,这里简单说一下:1、__stdcall调用约定相当于16位动态库中经常使用的PASCAL调用约定。

在32位的VC++5.0中PASCAL调用约定不再被支持(实际上它已被定义为__stdcall。

除了__pascal外,__fortran和__syscall也不被支持),取而代之的是__stdcall调用约定。

两者实质上是一致的,即函数的参数自右向左通过栈传递,被调用的函数在返回前清理传送参数的内存栈,但不同的是函数名的修饰部分(关于函数名的修饰部分在后面将详细说明)。

_stdcall是Pascal程序的缺省调用方式,通常用于Win32 Api中,函数采用从右到左的压栈方式,自己在退出时清空堆栈。

VC将函数编译后会在函数名前面加上下划线前缀,在函数名后加上"@"和参数的字节数。

2、C调用约定(即用__cdecl关键字说明)按从右至左的顺序压参数入栈,由调用者把参数弹出栈。

对于传送参数的内存栈是由调用者来维护的(正因为如此,实现可变参数的函数只能使用该调用约定)。

另外,在函数名修饰约定方面也有所不同。

_cdecl是C和C++程序的缺省调用方式。

dll原理

dll原理

dll原理DLL原理动态链接库(Dynamic Link Library,简称DLL)是一种Windows 操作系统中常用的库文件,它可以被多个应用程序共享使用,从而避免了重复编写相同的代码。

本文将详细介绍DLL的原理。

一、静态链接与动态链接在介绍DLL原理之前,先来了解一下静态链接和动态链接。

1. 静态链接静态链接是指将程序所需要的库文件在编译时全部打包进可执行文件中。

这样做的好处是程序运行时不需要再加载外部库文件,因此速度较快。

但缺点也很明显,即可执行文件体积较大,在多个程序中使用相同的库时会造成重复浪费。

2. 动态链接动态链接是指在程序运行时才加载所需的库文件。

这样做的好处是节省了内存空间,并且多个程序可以共享同一个库文件。

但缺点也很明显,即运行速度较慢。

二、DLL概述1. DLL定义DLL是一个包含可由多个程序同时使用的代码和数据的库文件。

它可以被多个应用程序共享使用,从而避免了重复编写相同的代码。

2. DLL分类根据DLL所包含函数是否可以被其他应用程序调用,DLL可以分为两种类型:(1)导出函数的DLL导出函数的DLL是指将其中一些函数导出,以便其他应用程序可以调用这些函数。

这种DLL文件通常包含一组API(Application Programming Interface,应用程序编程接口)函数。

(2)内部使用的DLL内部使用的DLL是指不导出任何函数,只供当前进程中的其他模块使用。

这种DLL文件通常包含一些共享数据和实现某些功能的代码。

三、DLL加载过程1. 加载方式当一个应用程序需要调用一个DLL中的函数时,Windows操作系统会自动加载该DLL。

Windows操作系统有两种加载方式:(1)显式链接显式链接是指在编译时就将要使用的DLL文件名和需要调用的函数名写入源代码中,并在程序运行时由操作系统自动加载该DLL文件。

(2)隐式链接隐式链接是指在编译时不将要使用的DLL文件名和需要调用的函数名写入源代码中,而是在程序运行时由操作系统自动搜索并加载相应的DLL文件。

__declspec 和 DLL导出函数

__declspec 和 DLL导出函数

__cdecl和__stdcall都是函数调用规范(还有一个__fastcall),规定了参数出入栈的顺序和方法,如果只用VC编程的话可以不用关心,但是要在C++和Pascal等其他语言通信的时候就要注意了,只有用相同的方法才能够调用成功.另外,像printf这样接受可变个数参数的函数只有用cdecl才能够实现.__declspec主要是用于说明DLL的引出函数的,在某些情况下__declspec(dllexport)在DLL中生命引出函数,比用传统的DEF文件方便一些.在普通程序中也可以用__declspec(dllimport)说明函数是位于另一个DLL中的导出函数.例子不太好举啊,其实就是在函数声明的时候多加一个关键字,比如很多API函数就是象这样声明的:int WINAPI MessageBoxA(HWND,LPCSTR,LPSTR,UINT);而WINAPI实际上就是__stdcall.大多数API都采用__stdcall调用规范,这是因为几乎所有的语言都支持__stdcall调用.相比之下,__cdecl只有在C语言中才能用.但是__cdecl调用有一个特点,就是能够实现可变参数的函数调用,比如printf,这用__stdcall调用是不可能的.__fastcall这种调用规范比较少见,但是在Borland C++ Builder中比较多的采用了这种调用方式.如果有共享代码的需要,比如写DLL,推荐的方法是用__stdcall调用,因为这样适用范围最广.如果是C++语言写的代码供Delphi这样的语言调用就必须声明为__stdcall,因为Pascal不支持cdecl调用(或许Delphi的最新版本能够支持也说不定,这个我不太清楚).在其他一些地方,比如写COM组件,几乎都用的是stdcall调用.在VC或Delphi或C++Builder里面都可以从项目设置中更改默认的函数调用规范,当然你也可以在函数声明的时候加入__stdcall,__cdecl,__fastcall关键字来明确的指示本函数用哪种调用规范.__declspec一般都是用来声明DLL中的导出函数.这个关键字也有一些其他的用法,不过非常罕见.关于DLL的函数:动态链接库中定义有两种函数:导出函数(export function)和内部函数(internal function)。

scope的用法

scope的用法

scope的用法一级标题:了解scope的概念在编程领域中,scope(作用域)是指变量、函数和对象可被访问的范围。

它确定了在代码中何处可以使用这些标识符以及在何处无法使用。

理解和正确使用scope是编写高效、可维护和安全代码的关键。

二级标题1:全局作用域全局作用域是程序中最外层的作用域,其中定义的变量、函数和对象可以在整个代码中被访问。

全局作用域中声明的变量称为全局变量。

它们可以通过任何其他作用域来访问。

然而,滥用全局变量可能导致命名冲突、内存泄漏和代码难以维护等问题。

因此,在编写代码时,应尽量避免过多地依赖于全局作用域。

二级标题2:局部作用域局部作用域是指在特定块或函数内部声明的范围,它仅限于该块或函数内部。

在JavaScript中,每当创建一个新的函数时,就会创建一个新的局部作用域。

在不同的函数中可以有相同名称的变量,因为它们存在各自独立的作用域中并不会相互影响。

这种方式提供了良好的封装性,可以防止变量之间的意外冲突。

二级标题3:块级作用域块级作用域是指由一对花括号({})包围的代码片段。

在ES6之前,JavaScript中只有全局作用域和函数作用域,没有块级作用域。

然而,ES6引入了let和const关键字,使开发人员能够在语句块内部创建块级作用域。

使用块级作用域可以有效地控制变量的可见范围,并避免变量泄漏到周围的代码中。

通常,在循环或条件语句中声明的变量应该属于块级作用域。

二级标题4:词法作用域词法作用域是指在代码编写时定义变量的位置决定了其可见范围。

与词法作用域相对应的是动态作用域,在运行时根据调用堆栈决定变量的可见性。

大多数编程语言(包括JavaScript)都使用词法作用域来确定标识符的解析方式。

这意味着一个函数总是在其被定义的位置查找变量,而不是执行时所处的位置。

二级标题5:函数作用域与闭包函数作为一种特殊类型的对象,具有其自己的作用域。

在函数内部定义的变量可以通过该函数的作用域进行访问,但无法在外部访问。

详解模块定义(.def)文件

详解模块定义(.def)文件

在模块定义文件中,DESCRIPTION 仅在生成虚拟设备驱动程序 (VxD) 时有效。
EXETYPE:dynamic | dev386
在模块定义文件中,EXETYPE 仅在生成虚拟设备驱动程序 (VxD) 时有效。如果生成虚拟设备驱动程序时在模块定义文件中没有指定 EXETYPE,并且如果没有指定 /EXETYPE 链接器选项,则静态加载 (dev386) 生效。
BASE=address 参数设置操作系统用来加载 DLL 的基址。该参数重写 0x10000000 的默认 DLL 位置。有关基址的详细信息,请参阅 /BASE 选项说明。
请记住,在生成 DLL 时使用 /DLL 链接器选项。
/HEAP:reserve[,commit]
.def 文件中的 EXPORTS 语句
LINK 命令中的 /EXPORT 规范
所有这三种方法可以用在同一个程序中。LINK在生成包含导出的程序时还创建导入库,除非生成中使用了 .exp 文件。
以下是 EXPORTS 节的示例:
Visual C++ 的早期版本支持:
section [CLASS 'classname'] specifier
出于兼容性考虑,支持 CLASS 关键字,但忽略了它。
另一种指定节属性的方法是使用 /SECTION 选项。
EXPORTS
func2=func1
@ordinal 允许指定是序号而不是函数名将进入 DLL 的导出表。这有助于最小化 DLL 的大小。.LIB 文件将包含序号与函数之间的映射,这使您得以像通常在使用 DLL 的项目中那样使用函数名。
可选的 NONAME 关键字允许只按序号导出,并减小结果 DLL 中导出表的大小。但是,如果要在 DLL 上使用 GetProcAddress,则必须知道序号,因为名称将无效。

不允许 dllimport 静态数据成员

不允许 dllimport 静态数据成员

不允许dllimport 静态数据成员“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所谓的…导出类‟了。

然而对模板却不行。

这里面还有涉及到编译器不能支持对模板的分离式编译的问题。

首先说一下编译器的大致的编译原理。

动态链接库

动态链接库

节省磁盘空间
更新产品更为容易
支持多语言程序
提供了扩展MFC类库的机制
隐藏实现的细节
拓展开发工具的功能
8.1.2 动态链接库的加载
应用程序调用动态链接库有两种方法:静态调用和 动态调用。
在静态调用时,使用DLL的可执行文件链接到此DLL提供 的导入库(.lib文件),可执行文件运行时就加载DLL。因 此,静态调用也称为隐式链接、静态加载或加载时动态链接。 在动态调用时,使用DLL的可执行文件必须进行函数调用, 显式地加载和卸载此DLL,并访问此DLL的导出函数。可执 行文件必须通过函数指针调用导出函数。因此,动态链接也 称为显式链接、动态加载或运行时动态链接。
8.1.1 动态链接库与静态链接库
静态链接库与动态链接库的最大区别是库代码 的链接时机。
动态链接库是在被应用程序调用的时候才同程 序相链接,链接操作由Windows操作系统来完成。 静态链接库是在应用程序被执行时就同程序相 链接,链接操作由链接器来完成。
使用动态链接库具有以下优点:
共享代码、资源和数据
DLLExample.def
DLL模块定义文件,这个文件在编译期 间使用。它包含DLL的名称,对于在 DLL中那些将要导出的项,可以选择在 此声明。
DLL项目的debug文件夹包含的主要文件:
引入库(.LIB)文件与DLL文件
引入库(.LIB)文件:引入库文件包含被DLL导出 的函数的名称和位置; DLL文件:DLL包含实际的函数和数据; 应用程序使用LIB文件链接到所需要使用的DLL文件, 库中的函数和数据并不复制到可执行文件中,因此 在应用程序的可执行文件中,存放的不是被调用的 函数代码,而是DLL中所要调用的函数的内存地址, 这样当一个或多个应用程序运行是再把程序代码和 被调用的函数代码链接起来,从而节省了内存资源。

#pragma comment用法

#pragma comment用法

#pragma comment在vc中,该宏(#pragma comment)放置一个注释到对象文件或者可执行文件。

我们经常用到的是#pragma comment(lib,"*.lib")这类的。

例如:#pragma comment(lib,"Ws2_32.lib")表示链接Ws2_32.lib这个库。

和在vc的工程设置里写上链入Ws2_32.lib的效果一样,不过这种方法写的程序别人在编译你的代码的时候就不用再设置工程settings了。

#pragma comment( comment-type [,"commentstring"] )comment-type是一个预定义的标识符,指定注释的类型,应该是compiler,exestr,lib,linker之一。

commentstring是一个提供为comment-type提供附加信息的字符串。

五种预定义的标识符为:1、compiler:将编译器的版本号和名称放入目标文件中,本条注释记录将被编译器忽略。

如果你为该记录类型提供了commentstring参数,编译器将会产生一个警告。

例如:#pragma comment( compiler )2、exestr:将commentstring参数放入目标文件中,在链接的时候这个字符串将被放入到可执行文件中。

当操作系统加载可执行文件的时候,该参数字符串不会被加载到内存中.但是,该字符串可以被dumpbin之类的程序查找出并打印出来,你可以用这个标识符将版本号码之类的信息嵌入到可执行文件中!3、lib:这是一个非常常用的关键字,用来将一个库文件链接到目标文件中。

常用的lib关键字,可以帮我们连入一个库文件。

例如: #pragma comment(lib, "user32.lib")该指令用来将user32.lib库文件加入到本工程中。

钩子函数使用

钩子函数使用
既可以是包含在一个.exe也可以是一个.dll。但是对于一个全局系统钩子,钩子函数必须包含在独立的dll中,因此,当我们要捕捉键盘响应时,我们必须创建一个
动态链接库。但是当钩子函数在得到了控制权,并对相关的事件处理完后,如果想要该消息得以继续的传递,那么则必须调用另一个函数:CallNextHookEx。
由于系统必须对每个消息处理,钩子程序因此增加了处理的负担,因此也降低了系统的性能。鉴于这一点,在windows ce中对钩子程序并不支持。所以当程序完成并退出时,
应当释放钩子,调用函数:UnhookWindowsHookEx。
下面我们将举一个例子(捕捉键盘)来详细的讲解钩子函数的程序设计。
三:程序的设计:
键盘敲打消息的信息,并且,键盘敲打消息一直没有从消息队列中删除。(应用程序调用PeekMessage函数,并且设置PM_NOREMOVE标志)。也就是说当nCode等于HC_ACTION时,
钩子进程必须处理消息。而为HC_NOREMOVE时,钩子进程必须传递消息给CallNextHookEx函数,而不能做进一步的处理,而且必须有CallNextHookEx函数的返回值。
}
DllExport LRESULT CALLBACK KeyBoardProc(int nCode,WPARAM wParam, LPARAM lParam )
{
WPARAM j;
FILE *fp;
if(lParam&0x80000000)
{
j = wParam;
fp=fopen("c:\\hook\\key.txt","a");
DllExport void EndHook(void);

dll导出函数的两种方式的比较

dll导出函数的两种方式的比较

dll导出函数的两种⽅式的⽐较最初的⽹页链接已经挂了, 在此贴⼀个中间的转载链接⼀概要 vs中导出 dll的⽅法有两种: ⼀种是使⽤__declspec(dllexport), 另⼀种就是使⽤.def⽂件⽅式, 这两种⽅式的最主要区别是在导出函数的名字上, 其次还有⼀些操作的灵活性上以及功能的强弱⼆⼀个具体的例⼦1 __declspec(dllexport) ⽅式⾸先对C和C++编译(extern "C")与调⽤约定(__cdecl、__stdcall、__fastcall)进⾏组合测试:<1> C++编译__declspec(dllexport) int add(int, int);__declspec(dllexport) int __cdecl add(int, int);__declspec(dllexport) int __stdcall add(int, int);__declspec(dllexport) int __fastcall add(int, int);对于C++编译器的函数名修饰规则:不管__cdecl, __fastcall还是__stdcall调⽤⽅式,函数修饰名都是以"?"开始,后⾯是函数在名字,再后⾯是函数返回类型和参数类型按照代号拼出的参数表。

对于__stdcall⽅式,参数表的开始标⽰是"@@YG”,对于__cdecl⽅式则是"@@YA”,对于__fastcall⽅式则是"@@YI”.参数表后以"@Z”标⽰整个名字的结束,如果该函数⽆参数,则以"Z”标识结束。

<2> C编译extern "C" __declspec(dllexport) int add(int, int);extern "C" __declspec(dllexport) int __cdecl add(int, int);extern "C" __declspec(dllexport) int __stdcall add(int, int);extern "C" __declspec(dllexport) int __fastcall add(int, int);<3> 备注__declspec(dllexport)的位置:To export functions, the __declspec(dllexport) keyword must appear to the left of the calling-convention keyword, if a keyword is specified.For example:__declspec(dllexport) void __cdecl Function1(void);To export all of the public data members and member functions in a class, the keyword must appear to the left of the class name as follows:class __declspec(dllexport) CExampleExport : public CObject{ class definition };2 def⽂件导出⽅式(项⽬中添加⼀个def后缀的⽂件, 然后在项⽬属性->连接器->所有选项->模块定义⽂件)具体到测试实例,我们的def⽂件内容如下:LIBRARY "win"EXPORTSadd @1其中LIBRARY指定dll的模块名称,即dll名字,EXPORTS后的每⼀⾏指定⼀个导出函数名字,这个名字和头⽂件中的声明⼀致,后⾯可以跟@序号指定该函数的序号(这个是可选的,后⾯按序号导⼊函数的时候再详细说)。

declspec(dllexport)与_declspec(dllimport)

declspec(dllexport)与_declspec(dllimport)

declspec(dllexport)与_declspec(dllimport)(转)2010-12-21 10:46:05| 分类:默认分类 | 标签:导出 dllimport __declspec dllexport 函数 |字号大中小订阅一部分:使用 __declspec(dllexport) 从 DLL 导出Microsoft 在 Visual C++ 的 16 位编译器版本中引入了__export,使编译器得以自动生成导出名并将它们放到一个 .lib 文件中。

然后,此 .lib 文件就可以像静态 .lib 那样用于与 DLL 链接。

在 32 位编译器版本中,可以使用__declspec(dllexport)关键字从 DLL 导出数据、函数、类或类成员函数。

__declspec(dllexport)会将导出指令添加到对象文件中,因此您不需要使用 .def 文件。

当试图导出 C++ 修饰函数名时,这种便利最明显。

由于对名称修饰没有标准规范,因此导出函数的名称在不同的编译器版本中可能有所变化。

如果使用__declspec(dllexport),仅当解决任何命名约定更改时才必须重新编译 DLL 和依赖 .exe 文件。

许多导出指令(如序号、NONAME 和 PRIVATE)只能在 .def 文件中创建,并且必须使用 .def 文件来指定这些属性。

不过,在 .def 文件的基础上另外使用__declspec(dllexport)不会导致生成错误。

若要导出函数,__declspec(dllexport)关键字必须出现在调用约定关键字的左边(如果指定了关键字)。

例如:__declspec(dllexport) void __cdecl Function1(void);若要导出类中的所有公共数据成员和成员函数,关键字必须出现在类名的左边,如下所示:class __declspec(dllexport) CExampleExport : public CObject{ ... class definition ... };生成 DLL 时,通常创建一个包含正在导出的函数原型和/或类的头文件,并将__declspec(dllexport)添加到头文件中的声明中。

c++中__declspec的用法详解

c++中__declspec的用法详解

c++中__declspec的⽤法详解c++ 中__declspec 的⽤法如下,想要了解的继续往下看吧。

语法说明:__declspec ( extended-decl-modifier-seq )扩展修饰符:1:align(#)⽤__declspec(align(#))精确控制⽤户⾃定数据的对齐⽅式,#是对齐值。

e.g__declspec(align(32))struct Str1{int a, b, c, d, e;};它与#pragma pack()是⼀对兄弟,前者规定了对齐的最⼩值,后者规定了对齐的最⼤值。

同时出现时,前者优先级⾼。

__declspec(align())的⼀个特点是,它仅仅规定了数据对齐的位置,⽽没有规定数据实际占⽤的内存长度,当指定的数据被放置在确定的位置之后,其后的数据填充仍然是按照#pragma pack规定的⽅式填充的,这时候类/结构的实际⼤⼩和内存格局的规则是这样的:在__declspec(align())之前,数据按照#pragma pack规定的⽅式填充,如前所述。

当遇到__declspec(align())的时候,⾸先寻找距离当前偏移向后最近的对齐点(满⾜对齐长度为max(数据⾃⾝长度,指定值)),然后把被指定的数据类型从这个点开始填充,其后的数据类型从它的后⾯开始,仍然按照#pragma pack填充,直到遇到下⼀个__declspec(align())。

当所有数据填充完毕,把结构的整体对齐数值和__declspec(align())规定的值做⽐较,取其中较⼤的作为整个结构的对齐长度。

特别的,当__declspec(align())指定的数值⽐对应类型长度⼩的时候,这个指定不起作⽤。

2: allocate("segname")⽤__declspec(allocate("segname")) 声明⼀个已经分配了数据段的⼀个数据项。

declval用法

declval用法

declval用法declval用法详解在C++中,declval是一个非常有用的模板函数,它用于产生一个类型的右值引用,用于在编译时获取类型相关信息而不实际创建对象。

下面列举一些常见的declval用法,并详细介绍它们的用途和使用方法。

1. 获取类型的右值引用declval最常见的用法就是用于获取类型的右值引用。

通过使用declval可以在编译时获取一个未实例化类型的右值引用,而无需实际创建该类型的对象。

这是在某些需要类型信息的上下文中非常有用的。

template <typename T>void foo(T&& t) {// 使用declval获取类型T的右值引用T&& ref = std::declval<T>();// ...}上面的例子中,foo是一个模板函数,参数为一个通用引用T&& t。

通过使用declval,我们可以直接获取到类型T的右值引用,并将其赋值给ref变量。

2. 构造返回类型declval还可以用于构造返回类型。

当需要定义一个函数的返回类型时,如果依赖于某个模板参数的类型,可以使用declval来获取该模板参数的右值引用,并通过decltype关键字来推导出返回类型。

template <typename T>auto create() -> decltype(std::declval<T>()()) {return T()();}在上面的例子中,create函数返回类型的定义中使用了declval,它用于获取模板参数T的右值引用。

通过decltype关键字,我们可以根据T()表达式的推导结果来定义返回类型。

3. 用于类型特化在一些特殊情况下,我们需要将一个模板函数进行特化,以适应某个特定类型。

这时,declval可以帮助我们获取到该特定类型的右值引用,以便在特化版本中使用。

LCF文件使用说明

LCF文件使用说明

序言:Codewarrior 2.10是飞思卡尔32位汽车级单片机Qorriva系列的集成开发环境,与之前版本2.8、2.9完全兼容。

Codewarrior 10.3是飞思卡尔最新的集成开发环境,是一个开放源代码的、基于Java的可扩展开发平台。

许多新用户对codewarrior链接文件不是十分了解,本文将针对链接文件的常见问题以及段的定义进行介绍帮助用户快速了解和使用CodeWarrior。

目录第一节LCF文件定义及使用说明1并且代码要在程序开始执行的时候从ROM去拷贝到RAM区。

下面是一个完整的lcf文件,其中包括每行的解释及用法。

/* lcf file for MPC5604B M27V (debug RAM version) 文件的名字及对应单片机(RAM版本)*///RAM版本和ROM版本的区别在于RAM版本不将程序下载到ROM中去,而在RAM中执行程序/* 512KB Flash, 32KB SRAM */ //单片机的FLASH和SRAM大小MEMORY下面是对单片机存储空间的定义,不同的段的起始地址,不能叠加地址空间{pseudo_rom:(仿真ROM区)org = 0x40000000, (开始地址)len = 0x00003000(长度)init: org = 0x40004000, len = 0x00001000 //初始化段所在位置exception_handlers: org = 0x40005000, len = 0x00001000 //中断向量所在地址internal_ram: org = 0x40006000, len = 0x00001800 //内部RAM的起始地址heap : org = 0x40007800, len = 0x00000400 //堆的起始地址stack : org = 0x40007C00, len = 0x00000400 //栈的起始地址}SECTIONS段的定义{GROUP : { // 它的定义需要遵从本例程方式”GROUP:{}” .“{}”中是内容部分.init : {} //.init段中所有内容。

【Example】C++接口概念讲解及例子演示

【Example】C++接口概念讲解及例子演示

【Example】C++接⼝概念讲解及例⼦演⽰C++ 和 Java 不同的是,C++ 没有 interface 关键字。

对于很多新⼿来说,C++ 当中接⼝的概念不容易像 Java 当中那样被理解。

然⽽接⼝是⾯向对象编程当中的重要组成部分,也是新⼿需要学习的重要思维,虽然 C++ 并不那么⾯向对象。

⾸先,要明确接⼝的概念:接⼝的存在意义是为不同的派⽣类提供统⼀的标准,继⽽实现⾯向对象编程当中的多态概念。

对象是对客观事物的抽象,类是对对象的抽象。

那么,C++ 当中既然不存在 interface 关键字,那么接⼝是通过什么⽅式来实现的呢?⾸先要讲两个概念:⼀、纯虚函数 (Pure Virtual Function):1,纯虚函数只有函数名、参数、返回值类型。

2,纯虚函数的定义是在函数句⾸使⽤ virtual 关键字修饰,并且在句末增加 "= 0"。

virtual void funtion() = 0;3,纯虚函数不能包含实现,只有声明,所以纯虚函数不能被调⽤。

4,定义纯虚函数的⽬的在于,使每⼀个派⽣类都拥有相同的函数规范。

承上启下:包含纯虚函数的类就是抽象类。

⼆、抽象类 (Abstract Class):1,抽象类必须包含⼀个纯虚函数,存在纯虚函数的类就⼀定是⼀个抽象类。

2,抽象类不能被实例化,只能被继承派⽣,因为纯虚函数没有函数体,不是完整的函数,⽆法调⽤,也⽆法为其分配内存空间。

3,派⽣出来的⼦类必须实现所有抽象类当中的纯虚函数。

4,抽象类默认存在隐式的构造函数,但是不能将构造函数定义为纯虚函数。

(因为⽆意义)5,析构函数可以定义成纯虚函数,相应的派⽣类也要给出析构函数的实现。

6,如果派⽣出来的⼦类没有实现⽗抽象类当中的所有纯虚函数,那⼦类仍然是抽象类。

所以,特点就很显⽽易见了,有这么⼀个“类”,它不能被实例化,只能被继承,⽽继承它的派⽣类必须要重写它声明的所有函数。

这就是接⼝的概念,为所有派⽣类提供了⼀个统⼀的规范可以实现多态。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

__declspec关键字详细用法__declspec用于指定所给定类型的实例的与Microsoft相关的存储方式。

其它的有关存储方式的修饰符如static与extern等是C和C++语言的ANSI规范,而__declspec是一种扩展属性的定义。

扩展属性语法简化并标准化了C和C++语言关于Microsoft的扩展。

用法:__declspec ( extended-decl-modifier )extended-decl-modifier参数如下,可同时出现,中间有空格隔开:align (C++)allocateappdomaindeprecated (C++)dllimportdllexportjitintrinsicnaked (C++)noaliasnoinlinenoreturnnothrow (C++)novtableprocessproperty(C++)restrictselectanythreaduuid(C++)1.__declspec关键字应该出现在简单声明的前面。

对于出现在*或&后面或者变量声明中标识符的前面的__declspec,编译器将忽略并且不给出警告。

2.要注意区分__declspec是修饰类型还是修饰变量:__declspec(align(8)) struct Str b;修饰的是变量b。

其它地方定义的struct Str类型的变量将不受__declspec(align(8))影响。

__declspec(align(8)) struct Str {};修饰的是struct Str类型。

所有该类型的变量都受__declspec(align(8))影响。

align:格式:__declspec(align(n)) declarator其中,n是对齐参数,其有效值是2的整数次幂(从1到8192字节),如2,4,8,16,32或64。

参数declarator是要设置对齐方式的数据。

1.使用__declspec(align(n))来精确控制用户自定义数据的对齐方式。

你可以在定义struct,union,class或声明变量时使用__declspec(align(n))。

2.不能为函数参数使用__declspec(align(n))。

3.如果未使用__declspec(align(#)),编译器将根据数据大小按自然边界对齐。

如4字节整数按4字节边界对齐;8字节double按8字节边界对齐。

类或结构体中的数据,将取数据本身的自然对齐方式和#pragma pack(n)设置的对齐系数中的最小值进行对齐。

4.__declspec(align(n))和#pragma pack(n)是一对兄弟,前者规定了对齐系数的最小值,后者规定了对齐系数的最大值。

5.当两者同时出现时,前者拥有更高的优先级。

即,当两者同时出现且值矛盾时,后者将不起作用。

6.当变量size大于等于#pragma pack(n)指定的n,而且__declspec(align(n))指定的数值n比对应类型长度小的时候,这个__declspec(align(n))指定将不起作用。

7.当#pragma pack(n)指定的值n大于等于所有数据成员size的时候,这个值n将不起作用。

allocate:格式:__declspec(allocate("segname")) declarator为数据指定存储的数据段。

数据段名必须为以下列举中的一个:code_segconst_segdata_seginit_segsectionappdomain:指定托管程序中的每个应用程序域都要有一份指定全局变量或静态成员变量的拷贝。

deprecated:与#pragma deprecated()的作用相同。

用于指定函数的某个重载形式是不推荐的。

当在程序中调用了被deprecated修饰的函数时,编译器将给出C4996警告,并且可以指定具体的警告信息。

该警告信息可以来源于定义的宏。

例如:// compile with: /W3#define MY_TEXT "function is deprecated"void func1(void) {}__declspec(deprecated) void func1(int) {}__declspec(deprecated("** this is a deprecated function **")) void func2(int) {}__declspec(deprecated(MY_TEXT)) void func3(int) {}int main() {func1();func1(1); // C4996,警告信息:warning C4996: 'func1': was declared deprecatedfunc2(1); // C4996,警告信息:warning C4996: 'func2': ** this is a deprecated function ** func3(1); // C4996,警告信息:warning C4996: 'func3': function is deprecated}dllimport,dllexport:格式:__declspec( dllimport ) declarator__declspec( dllexport ) declarator分别用来从dll导入函数,数据,或对象以及从dll中导出函数,数据,或对象。

相当于定义了dll的接口,为它的客户exe或dll定义可使用的函数,数据,或对象。

将函数声明成dllexport就可以免去定义模块定义(.DEF)文件。

dllexport代替了__export关键字。

被声明为dllexport的C++函数导出时的函数名将会按照C++规则经过处理。

如果要求不按照C++规则进行名字处理,请使用.def文件或使用extern "C"。

jitintrinsic:格式:__declspec(jitintrinsic)用于标记一个函数或元素是64位通用语言运行时(CLR)。

主要用于Microsoft提供的某些库中。

使用jitintrinsic会在函数签名中加入MODOPT(IsJitIntrinsic)。

naked:格式:__declspec(naked) declarator此关键字仅用于x86系统,多用于虚拟设备驱动。

此关键字可以使编译器在生成代码时不包含任何注释或标记。

仅可以对函数的定义使用,不能用于数据声明、定义,或者函数的声明。

noalias:仅适用于函数,它指出该函数是半纯粹的函数。

半纯粹的函数是指仅引用或修改局部变量、参数和第一层间接参数。

它是对编译器的一个承诺,如果该函数引用全局变量或第二层间接指针参数,则编译器会生成中断应用程序的代码。

restrict:格式:__declspec(restrict) return_type f();仅适用于返回指针的函数声明或定义,如,CRT的malloc函数:__declspec(restrict) void *malloc(size_t size);它告诉编译器该函数返回的指针不会与任何其它的指针混淆。

它为编译器提供执行编译器优化的更多信息。

对于编译器来说,最大的困难之一是确定哪些指针会与其它指针混淆,而使用这些信息对编译器很有帮助。

有必要指出,这是对编译器的一个承诺,编译器并不对其进行验证。

如果您的程序不恰当地使用__declspec(restrict),则该程序的行为会不正确。

noinline:因为在类定义中定义的成员函数默认都是inline的,__declspec(naked)用于显式指定类中的某个函数不需要inline(内联)。

如果一个函数很小而且对系统性能影响不大,有必要将其声明为非内敛的。

例如,用于处理错误情况的函数。

noreturn:一个函数被__declspec(noreturn)所修饰,那么它的含义是告诉编译器,这个函数不会返回,其结果是让编译器知道被修饰为__declspec(noreturn)的函数之后的代码不可到达。

如果编译器发现一个函数有无返回值的代码分支,编译器将会报C4715警告,或者C2202错误信息。

如果这个代码分支是因为函数不会返回从而无法到达的话,可以使用约定__declspec(noreturn)来避免上述警告或者错误。

将一个期望返回的函数约定为__declspec(noreturn)将导致未定义的行为。

在下面的这个例子中,main函数没有从else分支返回,所以约定函数fatal为__declspec(noreturn)来避免编译或警告信息。

__declspec(noreturn) extern void fatal () {}int main() {if(1)return 1;else if(0)return 0;elsefatal();}nothrow:格式:return-type __declspec(nothrow) [call-convention] function-name ([argument-list])可用于函数声明。

告诉编译器被声明的函数以及函数内部调用的其它函数都不会抛出异常。

novtable:可用于任何类声明中,但最好只用于纯接口类,即类本身从不实例化。

此关键字的声明将阻止编译器对构造和析构函数的vfptr的初始化。

可优化编译后代码大小。

如果试图实例化一个用__declspec(novtable)声明的类然后访问类中成员,则会在运行时产生访问错误(access violation,即A V)。

process:表示你的托管应用程序进程应该拥有一份指定全局变量,静态成员变量,或所有应用程序域共享的静态本地变量的拷贝。

在使用/clr:pure进行编译时,应该使用__declspec(process),因为使用/clr:pure进行编译时,在默认情况下,每个应用程序域拥有一份全局和静态变量的拷贝。

在使用/clr进行编译时,不必使用__declspec(process),因为使用/clr进行编译时,在默认情况下,每个进程有一份全局和静态变量的拷贝。

只有全局变量,静态成员变量,或本地类型的本地静态变量可以用__declspec(process)修饰。

在使用/clr:pure进行编译时,被声明为__declspec(process)的变量同时也应该声明为const类型。

如果想每个应用程序域拥有一份全局变量的拷贝时,请使用appdomain。

相关文档
最新文档