除其他外,还有两种类型的调用约定--stdcall和cdecl.我对他们几乎没有问题:
我正在开发一个相当大的代码库,其中C++函数是从C#调用P /.
我们的代码库中有很多调用,比如......
C++:
extern "C" int __stdcall InvokedFunction(int);
Run Code Online (Sandbox Code Playgroud)
使用相应的C#:
[DllImport("CPlusPlus.dll", ExactSpelling = true, SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
private static extern int InvokedFunction(IntPtr intArg);
Run Code Online (Sandbox Code Playgroud)
我已经搜索了网(在我有能力的范围内),因为为什么存在这种明显的不匹配.例如,为什么C#中有Cdecl,而C++中有__stdcall?显然,这会导致堆栈被清除两次,但是,在这两种情况下,变量都以相同的相反顺序被压入堆栈,这样我就不会看到任何错误,尽管在发生的情况下可能会清除返回信息.在调试期间尝试跟踪?
来自MSDN:http: //msdn.microsoft.com/en-us/library/2x8kf7zx%28v=vs.100%29.aspx
// explicit DLLImport needed here to use P/Invoke marshalling
[DllImport("msvcrt.dll", EntryPoint = "printf", CallingConvention = CallingConvention::Cdecl, CharSet = CharSet::Ansi)]
// Implicit DLLImport specifying calling convention
extern "C" int __stdcall MessageBeep(int);
Run Code Online (Sandbox Code Playgroud)
再一次,extern "C"
C++代码和CallingConvention.Cdecl
C#中都有.为什么不CallingConvention.Stdcall
呢?或者,此外,为什么__stdcall
C++中存在?
提前致谢!
我听说过一些方法,但都没有卡住.我个人试图避免C中的复杂类型,并尝试将它们分解为组件typedef.
我现在面临着从一个所谓的"三星级程序员"维护一些遗留代码的问题,而且我很难阅读一些***代码[] [].
你如何阅读复杂的C声明?
我会听一些人说__fastcall
比这更快__cdecl
并且__stdcall
导致它将两个参数放入寄存器,而不是其他一个调用; 但是,另一方面,这不是C中使用的标准.
我想知道什么是__fastcall
不合适的,就像C中的标准,以及何时我将在我的代码中使用它.
下面D::foo
通过指向成员函数调用函数的方法将产生错误:必须使用.*
或->*
调用'f(...)'中的指针到成员函数...
当然这不是我们如何调用指针到 -成员职能.
正确的呼叫方式是(d.*f)(5);
OR(p->*f)(5);
我的问题是,'有没有办法在没有左侧的类对象的情况下调用类的成员函数?我想知道我们是否可以将class object(this
)作为常规参数传递?
在我看来,在一天结束时(在汇编/二进制级别),类的所有成员函数都是普通函数,它们应该在n + 1个参数上运行,其中(+ 1表示this
)
如果我们谈论D::foo
下面的函数,在汇编/二进制级别它应该运行两个参数:
this
)int
.那么,有没有一种方法(或hack)调用D::foo
传递给它的类对象作为函数参数而不是. or -> or .* or ->*
在类对象上使用运算符?
示例代码:
#include <iostream>
using namespace std;
class D {
public:
void foo ( int a ) {
cout << "D" << endl;
}
int data;
};
//typedef void __cdecl ( D::* Func)(int);
typedef void ( D::* …
Run Code Online (Sandbox Code Playgroud) 我有一个第三方C API,需要一个__stdcall
回调函数.
我的代码有一个外部提供的 __cdecl
回调函数.
我无法将函数指针传递给C-API,因为它们被认为是不同的类型.
绕过类型系统并reinterpret_cast<>
自然地使用会导致运行时错误.
下面是一个例子在这里:
// C-API
// the stdcall function pointer type:
typedef CTMuint(__stdcall *CTMwritefn)(const void *aBuf, CTMuint aCount, void *aUserData);
// A function needing the callback:
CTMEXPORT void __stdcall ctmSaveCustom(CTMcontext aContext, CTMwritefn aWriteFn, void *aUserData, int *newvertexindex);
^^^^^^^^^^^^^^^^^^^
//////////////////////////////////////////////////////////////////////////////
// C++
CTMuint __cdecl my_func(const void *aBuf, CTMuint aCount, void *aUserData);
// I want to call here:
ctmSaveCustom(context, my_func, &my_data, nullptr);
// ^^^^^^^
Run Code Online (Sandbox Code Playgroud)
有没有办法安全地将一个调用约定的函数转换和/或包装到另一个调用约定中?
我确实通过传递一个调用第二个捕获lambda的casted …
我花了一整天研究这个,而且我不是更聪明的:
我有一个C#DLL,PInvokes C++ DLL中的方法.在调试模式下编译时我没有遇到任何问题,但在Release模式下编译时,我得到一个AccessViolationException.谷歌搜索这个问题告诉我,它可能是不合规的调用约定的问题.现在代码在C#中看起来像这样:
[return: MarshalAs(UnmanagedType.U1)]
[DllImport("Native.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern Boolean AMethod(Int32 mode, byte frame);
Run Code Online (Sandbox Code Playgroud)
在C++中:
extern "C" {
DLL_EXPORT bool AMethod(int mode, BYTE frame)
{
...
}
}
Run Code Online (Sandbox Code Playgroud)
我已经设置C++项目使用VS2010中的__cdecl调用约定进行编译,但我仍然得到AccessViolationException,我不知道我还能做什么.我应该注意我的C++ DLL使用第三方DLL,我不知道他们使用什么调用约定.
任何帮助,将不胜感激!
哦,我的开发机器上没有例外,只在我的目标系统上.
结构如何作为参数传递?
由于结构的大小比正常大,各个字段是否顺序通过?
如果是这样,它们是否与正常参数相反?
他们在cdecl和stdcall之间有什么区别吗?
有一些调用约定(例如pascal
,stdcall
),但就我而言,C 确实使用cdecl
(C 声明)。这些约定中的每一个在调用者将参数加载到堆栈上的方式上都略有不同,分别是由哪个(调用者/被调用者)进行清理。
谈到清理,这是我的问题。我不明白:有三种不同的东西吗?
或者我应该怎么看他们?
此外,这个问题的目标基本上是可变参数函数如何在像 Pascal 这样的调用约定中工作,或者stdcall
被调用者应该在哪里清除/清理/恢复(我不知道哪个操作)堆栈 - 但他不知道有多少参数它会收到。
编辑
为什么将参数压入堆栈的顺序如此重要?您仍然拥有第一个参数(不是来自省略号的稳定参数),它为您提供有关 - 例如 - 变量参数数量的信息。并且还有“监护人”,它可以添加到省略号标点符号中,并且可以用作独立于调用约定的变量部分结束的标记。在这个链接中,如果调用者和被调用者在搞乱它们之前都保存了它们的状态,那么为什么调用者和被调用者都应该恢复这些寄存器的值?不应该只有其中一个(例如调用者)在调用函数之前将它们保存在堆栈中,仅此而已?另外,在同一个链接上
“因此,堆栈指针 ESP 可能会上下移动,但 EBP 寄存器保持固定。这很方便,因为这意味着我们始终可以将第一个参数称为 [EBP + 8],而不管在功能。”
推送的变量和局部变量在内存中是连续的。使用 EBP 推荐他们的优势在哪里?即使堆栈大小发生变化,它们之间也永远不会有一些动态偏移。
我读过的材料之一是这个站点(只是开始),以便更好地了解堆栈帧到底是什么。然后我继续 yt 并找到了这些堆栈概述和调用堆栈教程,但他们不知何故错过了我需要的部分。当你调用函数时到底发生了什么(我不明白指令“调用地址”后跟下一个指令a push
值到堆栈上,这意味着返回值)。谁来控制退货地址?呼叫者,召集者?被叫方?当被调用者返回时,程序继续执行一条指令,该指令是从寄存器中读取操作或什么?