标题说明了一切.我特别谈论C/C++,因为他们都认为这是"实施问题".我认为,定义标准接口可以轻松构建模块系统,以及许多其他好东西.
如果他们定义了标准的ABI,C/C++会"丢失"什么?
在我的DLL中有一个我想要导出的方法.
//作品:
extern "C" __declspec(dllexport)
Run Code Online (Sandbox Code Playgroud)
//不会工作
__declspec(dllexport)
Run Code Online (Sandbox Code Playgroud)
C++导出:
extern "C" __declspec(dllexport) int Test();
Run Code Online (Sandbox Code Playgroud)
C#import:
[DllImport("CircleGPU2_32.DLL", EntryPoint = "Test",
CallingConvention = CallingConvention.StdCall)]
public static extern int Test();
Run Code Online (Sandbox Code Playgroud)
为什么我需要外部"C"?
我喜欢尝试许多不同的编程语言,但我真的永远不会在实际项目中使用它们,因为我需要的所有重要的库都是用C++编写的.
通常我必须编写一个非常耗时的C接口,所以我想知道是否存在可以无缝调用任何C++代码的编程语言?
Jason Turner在他的演讲中提议打破 C++ ABI 以保持该语言的发展。他还提到,如果出于兼容性原因需要,可以通过将 C++ 库包装到 C 库中来隔离 C++ ABI 更改。
27:30相关截图:
这里“BinaryLibrary”和“Old C++ stdlib”使用旧的 ABI,“NewExecutable”使用假设的更新 ABI。
据我了解,这是有效的,因为“BinaryLibrary”的旧 C++ ABI 被烘焙成具有更稳定接口的单独二进制文件。
但是什么让 C 成为一个好的替代方案呢?难道它的ABI也不能改变吗?
我的公司为第三方提供了一个DLL,它为他们提供了可用于连接我们应用程序的API函数.DLL是用VC9编写的,API函数使用VC的默认调用约定(__cdecl).第三方围绕此界面构建了应用程序.
我现在的任务是编写DLL的更新版本.我们希望DLL具有与旧的完全相同的接口,因此它们可以互换使用.不幸的是,我们的开发环境现在是CodeGear RAD Studio 2007,因此我必须使用它来编写DLL.
最好的解决方案是使旧的和新的DLL都将其函数导出为__stdcall.然后可以重新链接第三方应用程序以期望__stdcall函数,每个人都会很高兴.不幸的是,由于各种原因,这种情况不太可能发生
或者,我可以将我的DLL中的函数声明为__cdecl.第三方期望__cdecl功能,所以这似乎是一个很好的解决方案.遗憾的是CodeGear坚持在__cdecl函数的名称后附加下划线('_').这意味着第三方应用程序必须进行有条件调用,MyApiFunction(...)或者_MyApiFunction(...)取决于它们使用的DLL.
所以我的问题是,如何从我的新DLL导出API函数,使它们是__cdecl并且不带下划线('_')前缀?
在我看来,C库几乎从来没有问题混合使用不同版本编译的库或(有时)甚至不同的编译器,并且许多语言似乎能够直接或以最小的努力与C库交互.
这是因为ABI是标准的吗?
我正在尝试从 NASM 调用外部 C++ 函数。当我在谷歌上搜索时,我没有找到任何相关的解决方案。
C++
void kernel_main()
{
char* vidmem = (char*)0xb8000;
/* And so on... */
}
Run Code Online (Sandbox Code Playgroud)
国家安全管理协会
;Some calls before
section .text
;nothing special here
global start
extern kernel_main ;our problem
Run Code Online (Sandbox Code Playgroud)
运行编译这两个文件后,我收到此错误:kernel.asm(.text+0xe): undefined reference to kernel_main'
这里有什么问题?谢谢。
我在结构中声明了联合数据类型(但有两种不同的语法)。对于结构的大小,我得到不同的输出。这里有什么收获?
union u {
double x;
int y;
};
union {
double x;
int y;
} u_1;
struct s1 {
int a;
union {
int b;
double c;
};
};
struct s2 {
int a;
union u{
int b;
double c;
};
};
int main()
{
u u1;
s1 s_1;
s2 s_2;
cout<< sizeof(u1)<< " "<<sizeof(u_1)<<" " <<sizeof(s_1)<<" " <<sizeof(s_2);
}
Run Code Online (Sandbox Code Playgroud)
我期望输出:8 8 16 16但实际输出是8 8 16 4。
如果您想将此问题标记为重复,请注意我已经阅读了有关此主题的问题,但我仍然不清楚.我的印象是,当包含C头并使用C代码链接时使用此构造(如果我错了,请纠正我).这是否意味着在不处理目标文件时我永远不必使用"extern C"?如果我错了,为什么旧C代码不能编译为C++,因为它最有可能是合法的c ++代码?
我对它有点不确定因为我发誓我在使用C++中的旧C 源代码时遇到过这种情况,其中链接器错误仅通过"extern C"解决,并且库头确实有
#ifdef __cplusplus
#extern "C"{
#endif
//......
#ifdef _cplusplus
}
#endif
Run Code Online (Sandbox Code Playgroud)
在他们旁边.
编辑:很抱歉不清楚,但我想问的是,只有在包含C头并链接到预先存在的C对象文件时才需要"extern C"吗?如果它是真的,(并且它似乎从下面的评论来判断),为什么库标题周围有"extern C"子句,为什么它们不能被包含并编译为C++?