int (HWND,,LPSTR,UINT);
事实上确实如此。
大多数API都使用调用约定,因为几乎所有语言都支持调用。
相比之下,它只能在C语言中使用。 但是call有一个特点,就是可以实现可变参数的函数调用。
例如,这对于呼叫来说是不可能的。
这种调用规范比较少见,但这种调用方式在C++中被广泛使用。
如果需要共享代码,比如写DLL,推荐的方法是使用调用,因为这样的适用范围最广。
如果代码是用 C++ 语言编写的并且由这种语言调用,则必须将其声明为:
因为它不支持cdecl调用(也许最新版本可以支持,我不确定)。
在其他地方,比如编写COM组件,几乎都会用到调用。
您可以从 VC 或 C++ 的项目设置中更改默认函数调用规范。
当然,你也可以在声明函数时添加 , 关键字,以明确表明该函数使用哪种调用约定。
它通常用于声明 DLL 中的导出函数。 该关键字还有一些其他用途,但非常罕见。
主要用于描述DLL的导出函数。 在某些情况下,() 用于声明 DLL 中的导出函数。
它比使用传统的 DEF 文件更方便。 在普通程序中,也可以使用()来表示该函数是位于另一个DLL中的导出函数。
这个例子并不容易给出。 其实无非就是在声明函数的时候多加一个关键字而已。 例如,许多 API 函数是这样声明的:
int (HWND,,LPSTR,UINT);
事实上确实如此。
大多数API都使用调用规范,因为几乎所有语言都支持调用。 相比之下,它只能用在C语言中。 但是有一个特点,就是可以实现可变参数的函数调用,比如,这是calls做不到的。
这种调用规范比较少见,但这种调用方式在C++中被广泛使用。
如果需要共享代码,比如写DLL,推荐的方法是使用调用,因为这样的适用范围最广。 如果代码是用C++语言编写的,并且被这样的语言调用,则必须声明为,因为不支持cdecl调用(也许最新版本可以支持,我对此不确定)。 在其他地方,比如编写COM组件,几乎都会用到调用。 在 VC 或 C++ 中,您可以从项目设置中更改默认函数调用规范。 当然,你也可以在声明函数时添加,,关键字,以明确表明该函数使用哪种调用规范。
它通常用于声明 DLL 中的导出函数。 该关键字还有一些其他用途,但非常罕见。
关于DLL函数:
动态链接库中定义了两种类型的函数:导出函数( )和内部函数( )。
导出函数可以由其他模块调用,内部函数在定义它们的 DLL 程序中使用。
输出函数有以下几种方式:
1、传统方法
在模块定义文件中指定要导入的函数或变量。 语法格式如下:
[=] [@[]] [数据] []
在:
是输出函数的名称或引用的数据;
相同的;
@表示输出表中的序号(索引);
仅在按序号输出时使用(不使用);
DATA 表示输出是一个数据项。 使用DLL输出数据的程序必须将数据项声明为()。
上述项目中,只有该项目为必填项目,其他项目可省略。
对于“C”函数,可以相当于函数名; 但对于“C++”函数(成员函数、非成员函数)
换句话说,它是一个修饰名。您可以从.map图像文件中获取要输出的函数的修饰名,或者使用
/get 然后将它们写入输出模块的.def 文件中。 它是VC提供的一个工具。
如果要输出“C++”类,请将要输出的数据和修改后的成员名称写入.def模块定义文件中。
2. 命令行输出
为链接器LINK指定/命令行参数并输出相关函数。
3、使用MFC提供的修饰符()
在要输出的函数、类、数据的声明前添加()修饰符,表示输出。
() 在C调用约定和C编译下,可以去掉输出函数名的下划线前缀。 “C”用 C++ 编写
可以使用C编译方法。 要在“C++”下定义“C”函数,需要添加“C”关键字。使用“C”
表示该函数使用C编译模式。 导出的“C”函数可以从“C”代码调用。
例如,在一个C++文件中,有以下函数:
"C" {void () 测试(int var);}
其输出函数名称为:Test
MFC 为此提供了一些宏。
:()
:()
:()
:()
:()
:()
:#ifdef
#别的
:#ifdef
#别的
:#ifdef
#别的
像这样的宏,如果在 DLL 应用程序的实现中使用,则表示输出(因为它是通过定义的)
该选项通常在编译器的识别参数/)中指定; 如果在使用 DLL 的应用程序中使用,则表示输入
(没有定义的)。
要输出整个类,请在类上使用 () ; 要输出类的成员函数,请使用该函数
()。 喜欢:
班级:
……
“C”无效();
这些方法中,更好采用第三种方法dll文件声明,方便好用; 第二种是之一种方法。 如果按序号输出,调用效率会更高;
最后一个是第二个。
//
模块定义文件 (.DEF)
模块定义文件 (.DEF) 是由一个或多个模块语句组成的文本文件,用于描述 DLL 的属性。 每个 DEF 文件必须至少
必须包含以下模块定义语句:
* 之一条语句必须是指示DLL名称的语句;
* 语句列出导出函数的名称; 下面列出要输出的函数的修改名称。 此名称必须匹配
定义的函数名称完全相同,因此您无需任何修改即可获得函数名称。
* 可以使用语句来描述DLL的用途(这句话是可选的);
*“;” 注释一行(可选)。
DLL程序和调用其输出函数的程序之间的关系
1.dll、进程、线程的关系
DLL 模块被映射到调用它的进程的虚拟地址空间。
DLL 使用的内存是从调用进程的虚拟地址空间分配的,并且只能由该进程的线程访问。
DLL的句柄可供调用进程使用; DLL可以使用调用进程的句柄。
DLL 使用调用进程的堆栈。
2. 关于共享数据段
DLL定义的全局变量可以被调用进程访问; DLL可以访问调用进程的全局数据。每个进程使用相同的DLL
每个进程都有自己的DLL全局变量实例。如果多个线程同时访问同一个变量,则需要使用同步机制; 为一个
对于DLL中的变量,如果希望使用该DLL的每个线程都有自己的值,则应该使用线程本地存储(TLS,
当地的 )。
设置数据段属性的目的也可以通过在程序中或者在开发环境的项目设置中添加预编译指令来达到。 你必须给
这些变量都被赋予了初始值,否则编译器会将没有初始值的变量放置在一个称为未初始化数据段中。
“C”指示编译器使用C语言方法来命名函数。
在制作DLL导出函数时,由于C++中函数重载的存在,
比如会调用DLL中的()(int,int),不同的编译器有不同的方法,导致使用获取地址时不方便。 使用“C”时,就不会出现上述情况,因为C没有函数重载,但是这样一来,“C”修饰的函数就不具备重载的能力,可以说与“C”不同”。
() 声明一个导出函数意味着这个函数应该从这个DLL中导出。 我想送给别人。一般用在dll中
() 声明导入函数意味着该函数是从另一个 DLL 导入的。 我想用。一般用在exe中使用某个dll
()可以减轻程序员的负担,满足线程本地存储的要求。 VC++ 允许将变量或结构声明为“线程本地”。 例如,以下声明如果放置在 DLL 中,将创建一个对于每个进程唯一的全局变量:
双字;
但如果这样声明,它对于每个线程都是唯一的:
() 双字;
每个以这种方式声明对象的 EXE 和 DLL 在可执行文件中都会有一个特殊的节 (),其中包含所有线程局部变量。 当加载 EXE 或 DLL 时,操作系统将识别此部分并进行适当的处理。 该部分 *** 作系统指定为“每个线程的本地部分”。
当加载 EXE 时,操作系统会扫描可执行文件和所有静态链接 () DLL 以查找所有线程本地部分。 所有部分的大小相加即可得出每个线程启动时应分配的内存量。
1. (align(16)) SS{ int a,b; };
它和#pack()是一对兄弟,前者指定对齐的最小值,后者指定对齐的更大值。 当它们同时出现时,前者的优先级更高。 (align())的一个特点是它只指定数据对齐的位置,但不指定数据实际占用的内存长度。 将指定的数据放置到某个位置后,后续的数据填充仍然按照#pack指定的方式填充。 此时类/结构体的实际大小和内存布局规则如下:在(align())之前,按照#pack指定的方式填充数据,如上所述。 遇到(align())时,首先找到距离当前偏移量最近的对齐点(满足对齐长度max(数据本身长度,指定值)),然后从该点开始指定数据类型,数据类型从后面开始之后,仍然按照#pack进行填充,直到遇到下一个(align())。 当所有数据填满后,将结构体的整体对齐值与(align())指定的值进行比较,取较大的作为整个结构体的对齐长度。 特别是,当 (align()) 指定的值小于相应类型的长度时,此指定不起作用。
2.#(“”,读)
/ (("")) int i = 0;
/ int main(){ 1;};
该关键字必须用在,,,, 关键字之后。 上面的例子使用了关键字。 使用该关键字将告诉编译器后续变量分配在哪个数据段中。
3. (()) void func(int) {}
与同。 在此声明之后,如果您在同一范围内使用 func(int) 函数,则会提醒您 c4996 警告。
4. ( )
& ( )
不用说,这两个关键字是用来导入和导出外部元素的。
5.()
用于将函数或元素标记为 64 位公共语言运行时。 没有看到具体的用法。
6.(裸)int func() {}
该关键字仅在x86系统中使用,并且多用于硬件驱动程序中。 该关键字使编译器生成没有任何注释或标签的代码。 它只能用于函数定义,不能用于数据声明、定义或函数声明。
7. () float * init(int m, int n) {};
&()void(float*a,float*b,float*c){}; // 必须用于优化!
() 只适用于返回指针的函数声明,如 () void *( size); 适用于返回非别名指针的函数。 该关键字在 C 运行时库实现中使用,因为它永远不会返回当前程序中已使用的指针值(除非您执行一些非法操作,例如在释放内存后使用内存)。 为编译器提供更多信息以执行编译器优化。 编译器面临的更大困难之一是确定哪些指针与其他指针混淆,使用此信息对编译器很有帮助。 需要指出的是,这是对编译器的承诺,并且未经编译器验证。 如果您的程序使用不当,该程序将出现错误行为。 ()也只适用于函数,这表明该函数是半纯函数。 半纯函数是指仅引用或修改局部变量、参数和一级间接参数的函数。 这是对编译器的承诺,如果函数引用全局变量或二级间接指针参数,编译器将生成会破坏应用程序的代码。
8.X类{
/()int(){0; /* 将不会 */ };
未经允许不得转载! 作者:admin,转载或复制请以超链接形式并注明出处天心神途传奇手游发布网。
原文地址:《学习C++函数调用约定(一)》发布于:2024-03-18




还没有评论,来说两句吧...