如何使用 Delphi 正确地静态 link C?

How to properly statically link C with Delphi?

我怎样才能正确静态 link C 和 Delphi? Delphi 吐出一条错误消息:

[dcc32 错误]Project1.dpr(15): E2065 不满足转发或外部声明:'Test'

C 编译器是带有 COFF 目标文件的 Visual C++。

Delphi:

program Project1;

{$L C:\Source.obj}

function Test(): Integer; cdecl; external;

begin
  WriteLn(Test);
end.

C:

extern "C" int __cdecl Test()
{
    return 12;
}

int main()
{
    return 0;
}

这取决于您使用的 C 编译器使用的名称修饰。例如,32 位 bcc32 编译器会将 Test 修饰为 _Test。所以 Delphi 到 link 的代码应该是:

function Test(): Integer; cdecl; external name '_Test';

但是编译器之间的装饰确实不同,你没有说你使用的是哪个编译器。如果上面的代码没有帮助,那么您应该使用 C 编译器的工具转储 obj 文件并检查其中的函数名称。

另一个问题是您实际上使用的是 C++ 编译器而不是 C 编译器。这可以从您对

的使用中看出
extern "C" 

这不是有效的 C。您应该删除它并切换到 C 编译器。将扩展名从 .cpp 更改为 .c 通常足以说服编译器将代码视为 C。

如果您开始从 C 标准库调用函数,例如 malloc 和朋友,那么您需要将 System.Win.Crtl 单元添加到您的 Delphi 代码的 uses 子句中。

另请注意,您不需要,实际上可能也不应该在 C 代码中实现 main 函数。如果要将 C 函数编译成单独的 C 程序,则将函数放在单独的源文件中,与包含 main 函数的源文件分开。这样你就可以将源文件编译成对象。您可以 link 它们进入 C 程序或您的 Delphi 代码。但是您不需要在 Delphi 程序中携带您不调用的 main 函数。

在 C 中,无参数 main 的正确签名是

int main(void)

同样,您的其他 C 函数应具有此签名:

int __cdecl Test(void)

当然,__cdecl 是默认值,因此我们完全可以忽略它:

int Test(void)

让我们把它们放在一起:

C

int Test(void)
{
    return 12;
}

重要的是您使用 C 编译器进行编译,而不是作为 C++ 进行编译。如果你的编译是,正如你现在在编辑中所说的那样,MSVC,命令行将是:

cl /c source.c

Delphi

{$APPTYPE CONSOLE}

{$L Source.obj}

function Test: Integer; cdecl; external name '_Test';

begin
  WriteLn(Test);
end.

输出

12