将参数推送到调用堆栈的可移植方法 (C++)
Portable way to push arguments onto the call stack (C++)
我正在编写一种小型脚本语言。
我正在寻找一种可移植的 C++ 方法来将参数推送到调用堆栈,以便我的函数正常读取它们。
这可能吗?它必须在 Visual Studio、XCode 和 Android Studio 中编译——最好使用 C++ 中嵌入的 asm(不能选择外部汇编文件)
没有可移植的方法(据我所知),因为 "call stack" 不是可移植的东西。一台机器可能有不同的调用堆栈实现,例如 PIC18 设备有单独的调用堆栈和变量堆栈,而 x86 共享使用相同的堆栈用于函数和变量和 return 值(用非常简单的话......) .
可能最好的办法是为您需要支持的每个体系结构和编译器创建一个单独的解决方案(宏或函数),然后使用处理器条件结构来区分它们。使用 gcc 编译器时,您可以使用 asm keyword and when running on x86 architecture you may use push instruction 将数据压入堆栈。
然后(半)可移植 方法是提供一个 API 实现在体系结构和编译器之间发生变化,就像这样:
// for gcc and clang compiler for x86 architecture
#if defined(__GNUC__) && defined(__i386__)
#define PUSH_VALUE_ONTO_THE_CALL_STACK(val) do{ \
/* this will break your code, dont use this */ \
int __v = (val); \
__asm__("push %0" : "r" (__v)); \
} while(0)
// for Visual Studio compiler x86 architecture
#elif defined(_MSC_VER) && defined(__i386__)
#define PUSH_VALUE_ONTO_THE_CALL_STACK(val) do{ \
/* this will break your code, dont use this */ \
__asm mov eax, val; \
__asm push eax; \
} while(0)
// add more
#elif defined(__PREDEFINED_MACRO_FOR_COMPILER) && defined(__PREDEFINED_MACRO_FOR_ARCHITECTURE)
#define PUSH_VALUE_ONTO_THE_CALL_STACK(val) /* implementation */
// when implementation is missing, issue a error
#else
#error Implementation PUSH_VALUE_ONTO_THE_CALL_STACK not found for Your architecture and compiler.
#endif
int main(void) {
// identical usage/api between compilers and architectures
PUSH_VALUE_ONTO_THE_CALL_STACK(5);
return 0;
}
希望这能让您走上正轨。
另外: XCode 只是 IDE 的名称,我认为 XCode 默认使用 clang。 Android 工作室 may use clang or gcc.
据我所知,没有可移植的方法。
此外,嵌入在 C++ 中的 asm 不可移植,MS Visual studio 在为 Win64 编译时不支持它。
解决此问题的一种方法是在 C 或 C++ 之上发明一些 ABI,适用于您的特定用例和脚本语言。这可以以便携方式完成,无需组装。
了解 MS 如何使用他们的 VBScript、IDispatch 和 VARIANT 数据类型做到这一点。
我并不是说您必须坚持使用 OLE 自动化 ABI,这只是一个示例。例如。如果您只将几个浮点值传递给您的函数,您可以执行以下操作:
int Invoke(IDFunc func, int argc, const float* argv)
,让您的脚本运行时将函数名称解析为 IDFunc 标识符,填充参数数组,然后调用 Invoke 函数。然后在互操作的 C++ 端调用正确的函数。您不再需要手动推送参数,您只需要分派函数调用,并且有很多方法可以实现,宏、模板、代码生成或它们的某种组合。
P.S。对于 MS OLE,IDFunc
数据类型是 int16,但您可以将其设为指向某物的指针,这可能有助于实现。
如果你有 C++ 17,可移植的方式是 std::apply。
Here’s a demo,参见 Engine\Function.hpp 源文件。
我正在编写一种小型脚本语言。
我正在寻找一种可移植的 C++ 方法来将参数推送到调用堆栈,以便我的函数正常读取它们。
这可能吗?它必须在 Visual Studio、XCode 和 Android Studio 中编译——最好使用 C++ 中嵌入的 asm(不能选择外部汇编文件)
没有可移植的方法(据我所知),因为 "call stack" 不是可移植的东西。一台机器可能有不同的调用堆栈实现,例如 PIC18 设备有单独的调用堆栈和变量堆栈,而 x86 共享使用相同的堆栈用于函数和变量和 return 值(用非常简单的话......) .
可能最好的办法是为您需要支持的每个体系结构和编译器创建一个单独的解决方案(宏或函数),然后使用处理器条件结构来区分它们。使用 gcc 编译器时,您可以使用 asm keyword and when running on x86 architecture you may use push instruction 将数据压入堆栈。
然后(半)可移植 方法是提供一个 API 实现在体系结构和编译器之间发生变化,就像这样:
// for gcc and clang compiler for x86 architecture
#if defined(__GNUC__) && defined(__i386__)
#define PUSH_VALUE_ONTO_THE_CALL_STACK(val) do{ \
/* this will break your code, dont use this */ \
int __v = (val); \
__asm__("push %0" : "r" (__v)); \
} while(0)
// for Visual Studio compiler x86 architecture
#elif defined(_MSC_VER) && defined(__i386__)
#define PUSH_VALUE_ONTO_THE_CALL_STACK(val) do{ \
/* this will break your code, dont use this */ \
__asm mov eax, val; \
__asm push eax; \
} while(0)
// add more
#elif defined(__PREDEFINED_MACRO_FOR_COMPILER) && defined(__PREDEFINED_MACRO_FOR_ARCHITECTURE)
#define PUSH_VALUE_ONTO_THE_CALL_STACK(val) /* implementation */
// when implementation is missing, issue a error
#else
#error Implementation PUSH_VALUE_ONTO_THE_CALL_STACK not found for Your architecture and compiler.
#endif
int main(void) {
// identical usage/api between compilers and architectures
PUSH_VALUE_ONTO_THE_CALL_STACK(5);
return 0;
}
希望这能让您走上正轨。
另外: XCode 只是 IDE 的名称,我认为 XCode 默认使用 clang。 Android 工作室 may use clang or gcc.
据我所知,没有可移植的方法。
此外,嵌入在 C++ 中的 asm 不可移植,MS Visual studio 在为 Win64 编译时不支持它。
解决此问题的一种方法是在 C 或 C++ 之上发明一些 ABI,适用于您的特定用例和脚本语言。这可以以便携方式完成,无需组装。
了解 MS 如何使用他们的 VBScript、IDispatch 和 VARIANT 数据类型做到这一点。
我并不是说您必须坚持使用 OLE 自动化 ABI,这只是一个示例。例如。如果您只将几个浮点值传递给您的函数,您可以执行以下操作:
int Invoke(IDFunc func, int argc, const float* argv)
,让您的脚本运行时将函数名称解析为 IDFunc 标识符,填充参数数组,然后调用 Invoke 函数。然后在互操作的 C++ 端调用正确的函数。您不再需要手动推送参数,您只需要分派函数调用,并且有很多方法可以实现,宏、模板、代码生成或它们的某种组合。
P.S。对于 MS OLE,IDFunc
数据类型是 int16,但您可以将其设为指向某物的指针,这可能有助于实现。
如果你有 C++ 17,可移植的方式是 std::apply。
Here’s a demo,参见 Engine\Function.hpp 源文件。