Delphi/C中更快的参数传递

3

我有两个应用程序,分别是Delphi和C语言编写的。我有两个问题: 1. 传递参数到Delphi的最快方法是什么?

procedure name(Data: string); // Data is Copied to another location before passing so its slow
procedure name(var Data: string); // Data is Passed by pointer, Faster
procedure name(const Data: string); // unknown
  1. i wanna pass parameters by pointers in c, i have a char array and a function, i don't wanna pass the whole array, cut a first part of it and pass the rest

    void testfunction(char **Data)
    {
        printf("Data = %d\n", *Data);
        return;
    }
    
    int main()
    {
        char Data[] = "TEST FUNCTION";
        testfunction(&&Data[4]);        // Error
        return 0;
    }
    

谢谢


1
如果您需要从C dll向Delphi传递字符串数据,请在Delphi接口中使用PAnsiChar或PWideChar类型,它们相当于LPCSTR(char *)和LPWSTR(wchar_t *)。 - Warren P
1
@Warren LPCSTR 实际上是 const char*。通常你会将 LPSTRLPWSTR 或者 LPCSTRLPCWSTR 配对使用。 - David Heffernan
1
没错。我不能再编辑那条评论了,所以感谢你注意到了这一点。 - Warren P
你的程序出现了崩溃,而你却在问关于速度的问题!首先要专注于正确性。一旦它能正常工作,再考虑速度。即使再快的速度也无法帮助一个不正确的程序。 - Rob Kennedy
4个回答

6
Delphi字符串存储在堆上并且总是通过指针传递。您的第一个按值传递的示例是不正确的。传递的字符串不会被复制,只有引用会被复制。这对于字符串是可能的,因为它们具有神奇的写时复制行为。传递的动态数组将被复制。
在传递字符串时使用const具有最佳性能,因为编译器可以优化出引用计数代码。
您的C代码有些混淆。不需要char **,而是需要char *。请记住,C字符串(即char*)只是指向空终止内存块的指针。您不需要取C字符串的指针,因为它已经是指针。
您肯定是想用%s而不是%d。要传递从第5个字符开始的C字符串,请编写Data+4。
 void testfunction(char *Data) {
     printf("Data = %s\n", Data);
 }

int main() {
    char Data[] = "TEST FUNCTION";
    testfunction(Data+4);
    return 0;
}

是的,我是指%s,抱歉,这对于C语言也会报错吗?我的意思是,在函数内部传递char *并对其进行修改与Delphi中的操作相同吗? - killercode
1
@killercode C字符串与Delphi字符串完全不同。在C中,您需要自己管理缓冲区。您可以修改C字符串中的字符,但是如果您想要在C中具有类似于“var s:string”的等效项,则确实需要使用char **。但是然后您需要释放旧字符串并重新分配新字符串(如果需要扩展它)。没有引用计数等。我使用了char *,因为您没有进行修改。这是为什么人们使用C++而不是C的许多原因之一。 - David Heffernan
1
是的,const 是最快的。不过它很少有影响。 - David Heffernan

3
自Delphi 2009版起,众所周知的事实是string=UnicodeString,因此将作为PWideChar/LPCWSTR导出,而不是PChar/LPCSTR。这个值得注意,因为如果你不清楚它,期望你的代码与所有版本的Delphi一起工作时可能会让人感到困惑。
如果您想要从C库中修改字符串内容,您应该使用WideString Delphi类型而不是stringWideString由Windows分配和处理(这是COM / Ole字符串),因此您拥有所有相应的C API来处理这些OLESTR指针。而且这个WideString不会受到Delphi 2009 Unicode断点的影响(它一直是Unicode)。
当然,WideStringstring慢(原因有几个,主要是WideString的堆分配速度更慢,自Vista以来得到了改善),但我认为这是一种安全的、跨语言的方式将一些文本数据导出到和从Delphi应用程序和库(在Windows世界中)中。例如,.Net世界将喜欢对这些OLESTR类型的变量进行封送处理。

2

我觉得代码有点误导人。它的意图是只打印“FUNCTION”吗?如果是这样:

void testfunction(const char *Data)
{
    printf("Data = %s\n", Data);
    return;
}

int main()
{
    char Data[] = "TEST FUNCTION";
    testfunction(Data+4);
    return 0;
}

这将把字符串从数组的第4个位置(包括第4个位置)传递给该函数。 通过传递char*,你不会在该函数的本地堆栈中复制该字符串。只是指向该内存开头的指针。


1

我只能回答Delphi部分(我的C语言有点生疏,当我处于最新状态时,C指针/数组引用会让我头痛)

字符串是指针,并且始终通过引用传递,因此在传递时不会复制数据。

然而,在某些情况下,例如

procedure test(s:String);

传递指针S,如果在test过程中修改S,则会生成一个唯一的字符串,并将新指针分配给S,而不是原始传递的变量。您可以传递字符串文字和字符串表达式/即时修改(s+'bla bla bla')。
procedure test(var s: String);

传递指针S的地址,

传递指针S,如果在过程test中修改S,则会生成唯一字符串(如有必要),并将新指针分配给S和原始传递的变量。您永远不能传递字符串字面值和现场修改的字符串表达式(s+'bla bla bla')。

procedure test(const s: string);

传递指针S,你不能在测试期间修改S。 (好吧,你可以胡闹并愚弄编译器,但这很丑陋,难以做到,并且通常需要大量类型转换)

这有点复杂。即使您不修改字符串,普通的按值传递会有引用计数开销。使用const可以避免这种情况。 - David Heffernan
@David Heffernan -> 啊对了,我忘记了它们是在递增内存值。不过,远比提问者所想的完全复制要少得多。 - C Johnson
好的,是的,比起完整的副本,这种情况不会发生!;-) 如果按值和const之间的区别很大,我会感到惊讶。 - David Heffernan
@David:当然,将纯输入参数声明为“const”也具有语义价值。 - Andreas Rejbrand
@Andreas 当然。由于问题的性质,我只关注了其中的某一方面。 - David Heffernan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接