问题标签 [cdecl]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
x86 - STDCALL vs CDECL:`ret` vs `sub esp`与调用约定有什么关系?
在Kip Irvine 的Assembly Language, Seventh Edition for x86 Processors中,第 325 页,它在8.2.4 32-Bit Calling Conventions下说,
C 调用约定... C 调用约定以一种简单的方式解决了清理运行时堆栈的问题:当程序调用子例程时,它会在
CALL
指令后面加上一条语句,将值添加到堆栈指针 (ESP
) 等于到子程序参数的组合大小。这是一个示例,其中两个参数(5 和 6)在执行CALL
指令之前被压入堆栈,因此,用 C/C++ 编写的程序总是在子程序返回后从调用程序的堆栈中删除参数。
它继续说
STDCALL 调用约定从堆栈中删除参数的另一种常用方法是使用名为 的约定
STDCALL
。在下面的AddTwo
过程中,我们为指令提供一个整数参数,RET
在返回调用过程后,它又将 8 加到 ESP 中。整数必须等于过程参数占用的堆栈空间字节数:应该指出的是
STDCALL
,像 C 一样,以相反的顺序将参数压入堆栈。通过在RET
指令中包含参数,STDCALL
减少了为子程序调用生成的代码量(通过一条指令),并确保调用程序永远不会忘记清理堆栈。另一方面,C 调用约定允许子例程声明可变数量的参数。调用者可以决定它将传递多少个参数。
c# - 堆已损坏:调用非托管函数时
我正在JNIDiskInfoDll.dll
从 C# 托管函数调用一个非托管且非常简单的 C++ 函数(位于 中),如下所示:
C++:
C#:
我的问题是,在运行应用程序后,我收到两个连续的错误,说projectName.exe has triggered a breakpoint
and Unhandled exception at 0x77110E23 (ntdll.dll) in projectName.exe: 0xC0000374: A heap has been corrupted (parameters: 0x7712E930).
。知道虽然我遇到了这些错误,但该函数仍在返回所需的输出。
请注意,getSerial
C 函数具有LPTSTR inCStrIn
参数,因为我在删除return "abcdefg";
错误仍然存在的整个代码(仅保留)之前使用它。
我不知道这里可能是什么问题。我试图将Charset
in更改DllImport
为Unidcode
,但仍然遇到相同的错误。请问有什么帮助吗?
c++ - __cdecl 和 (void) 是什么意思?
我目前正在使用 WSA 编写一个 tcp/ip 服务器。经过一些故障排除后,我的一个朋友说我应该使用bool __cdecl winsock_server ( void )
而不是bool winsock_server()
.
但他没有向我解释什么__cdecl
和(void)
正在做什么。我已经知道这__cdecl
改变了在汇编程序级别上将参数放入堆栈的方式,但这是什么(void)
意思?
我应该指出我是 C++ 新手。我以前只用 C# 和 VB.NET 编程过。
提前致谢!
c - 为什么两个双精度的结构通过寄存器传递,而三个双精度的结构通过堆栈传递?
以下代码:
编译为
在 Linux 上,x86-64 和 GCC 9.2 和 -O3(Godbolt 链接)
为什么两个双精度 ( Double2
) 的结构通过寄存器xmm0
和传递xmm1
,而三个双精度 ( Double3
) 的结构通过堆栈传递?double_args()
证明编译器至少能够通过寄存器传递三个双精度数。
这是否指定为 C 调用约定的一部分?相关规则是什么?
python - ctypes 如何推断传递的整数类型?
我正在连接这个 C 代码:
使用此 Python 代码:
即使我没有在print_int
代码中转换参数,它们也会正确传递,我得到:
正如预期的那样。为什么ctypes不能做同样形式的浮点数?以下片段:
将需要来自ctypes的显式强制转换,否则会引发异常。
我在 Unix 中工作,如果这很重要,则使用cdecl调用约定进行编译。
c# - 从 C# 调用 C++/CLR 函数 - 传递参数不起作用
我正在尝试从 C# dll 调用 C++/CLR dll 中的函数。-> 这工作得很好。
我面临的问题是应该从 C# 传递到 C++/CLR 中的函数的参数在 C++ 中没有正确到达。
最后,我需要将字符串数组和一些布尔参数从 C# 传递到 C++/CLR。
到目前为止我所做/尝试过的事情:
我的C++/CLR部分看起来像这样:
我的C#(dll 导入)部分如下所示:
C# 中的函数调用如下所示:
ID 定义如下:
c++ - 与函数指针、__cdecl 和模板混淆
在 Visual Studio 2019 中,我编写了以下测试代码,但结果让我很困惑。
(我知道我可以在使用时省略类型call
,但这是一个实验。)
我以为我能够理解从第 0 行到第 7 行的所有内容。我想到的square
是一个函数指针,所以它应该有 typeint (*) (int)
或者可能int(__cdecl*) (int)
,这两个要么相同,要么可以相互转换(我没有改变项目的调用约定,所以默认是__cdecl
)。
然而,令我惊讶的是第 8 行和第 9 行都能正确编译和运行。为什么会这样?
通过将第 6、7 行与第 8、9 行进行比较,我认为问题来自添加__cdecl
,但在Microsoft Docs中没有提到这样的内容。
然后我打印出类型:
看来square
确实有类型int (__cdecl) (int)
。另外,我不明白为什么square
并且*square
属于同一类型...
有人可以向我解释这些现象吗?
c++ - mingw - 正确运行函数所需的 cdecl
下面的代码可以在我找到的任何在线 gcc 编译器(gcc 9.2.0)上正确运行,它也可以在 CYGWIN gcc 编译器上正确运行,但不幸的是它不能与 MINGW gcc 编译器一起正常工作 - 看起来它传递了无效参数为“ this”到“methodA”和“methodB”方法,当它们被调用时,而不是预期的结果(56,58)我得到一些随机的高数字。
如果我将 __cdecl 属性添加到此方法,问题就解决了:
我不使用-mrtd 编译标志。据此, __cdecl 应该是 gcc 编译器的默认调用约定,但对于 MINGW 来说似乎并非如此。
是否可以将 __cdecl 设置为我的项目的默认调用约定?或者作为替代方案,有没有办法为所有方法设置“默认”属性?
我正在使用具有 64 位架构的 Windows 10。
c - 用于最大值的调用约定。x86 系统之间的可移植性
我正在研究一组独立的 x86 汇编例程,我希望这些例程可用于以下系统上的 C 程序:
- 仅限 Linux 64 位
- Windows 32 位和 64 位
- (很高兴最终拥有 64 位 Mac,但目前尚不清楚,因为 Apple 似乎正在放弃 x86 以支持 ARM)
我已经以其他方式使用 LLVM,几乎可以肯定我会使用 clang 而不是 gcc,尽管我可以设想有人想要使用 gcc 编译整个它的情况。汇编器将是 NASM。
我开发了例程和将它们公开给用户的 C 库,即一切都在我的控制之下,我可以根据需要设计一切。
我希望有些用户会真正使用 C++,但他们仍会链接到 C 库——也就是说,不会直接使用汇编程序。
由于我是汇编新手,我正在发现一个奇妙的迷宫,其中包含跨系统、编译器、供应商、调用变体和语言的各种调用约定。我不能说它有时不会带来有趣的阅读,但我也不能说它不会让初学者感到困惑。
在阅读完所有内容后,我的看法是,在一天结束时,我可以简单地从 cdecl 开始,以在初始版本中获得最大的可移植性,然后在需要时考虑使用特殊的外壳来涵盖其他约定 - 取决于例程实际执行的操作在特定情况下,我可以通过使用其他约定来使事情变得更快。
但最初,因为我希望有一些可以正常工作的东西,然后进一步优化它 - 说选择cdecl将在我列出的系统之间提供最大的可移植性是否正确?谢谢你。
c - C 调用约定:谁在可变参数函数和普通函数中清理堆栈?
有一些调用约定(例如pascal
,stdcall
),但就我而言,C 确实使用cdecl
(C 声明)。这些约定中的每一个在调用者将参数加载到堆栈上的方式上都略有不同,分别由哪个(调用者/被调用者)进行清理。
谈到清理,这是我的问题。我不明白:有三种不同的东西吗?
- 堆栈清洁
- 将指针移回倒数第二个堆栈帧
- 堆栈恢复
或者我应该怎么看他们?
此外,这个问题的目标基本上是可变参数函数如何在调用 Pascal 等约定或被stdcall
调用者应该清除/清理/恢复(我不知道哪个操作)堆栈的地方工作 - 但他不知道有多少参数它会收到。
编辑
为什么将参数压入堆栈的顺序如此重要?您仍然有第一个参数(不是来自省略号的稳定参数),它为您提供有关 - 例如 - 变量参数数量的信息。还有一个“守护者”可以添加到省略号标点符号中,并且可以用作变量部分结束的标记,独立于调用约定。在这个链接中,为什么调用者和被调用者都应该恢复这些寄存器的值,如果他们在搞砸之前都保存了他们的状态?不应该只有其中一个(例如调用者)在调用函数之前将它们保存在堆栈中,仅此而已?另外,在同一个链接上
“因此,堆栈指针 ESP 可能会上下波动,但 EBP 寄存器保持固定。这很方便,因为这意味着我们始终可以将第一个参数称为 [EBP + 8],而不管在其中完成了多少推送和弹出操作功能。”
推送变量和局部变量在内存中是连续的。使用 EBP 推荐他们的优势在哪里?即使堆栈大小发生变化,它们之间也永远不会有一些动态偏移。
我读过的材料之一是这个网站(只是开始),以便更好地了解stack frame的确切含义。然后我继续阅读并找到了这些堆栈概述和调用堆栈教程,但他们不知何故错过了我需要的部分。当你调用函数时到底发生了什么(我不明白指令“调用地址”后跟a push
堆栈上的下一个指令值,这意味着返回值)。谁控制退货地址?呼叫者,召集者?被调用者?当被调用者返回时,程序继续执行一条指令,该指令是从寄存器读取操作还是什么?