【问题标题】:Faster Parameter Passing in Delphi/CDelphi/C 中更快的参数传递
【发布时间】:2011-09-26 17:11:42
【问题描述】:

我有 2 部分应用程序,Delphi 和 C,我有 2 个问题 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. 我想通过 c 中的指针传递参数,我有一个 char 数组和一个函数,我不想传递整个数组,剪切它的第一部分并传递其余部分

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

谢谢

【问题讨论】:

  • 如果需要将字符串数据从C dll传递给Delphi,在delphi接口中使用PAnsiChar或PWideChar类型,相当于LPCSTR(char *)和LPWSTR(wchar_t *)。跨度>
  • @Warren LPCSTR 实际上是 const char*。通常你会配对LPSTRLPWSTRLPCSTRLPCWSTR
  • 没错。我无法再编辑该评论,因此感谢您注意到这一点。
  • -1 表示完全错误的前提。你的程序崩溃,你问的是速度!?首先关注正确性。一旦它工作,然后担心速度。单词中的所有速度都不会帮助错误的程序。

标签: c delphi parameters parameter-passing


【解决方案1】:

Delphi 字符串驻留在堆上并且总是通过指针传递。您的第一个按值传递示例不正确。按值传递的字符串不会被复制。仅复制参考。这对于字符串是可能的,因为它们具有神奇的写时复制行为。按值传递的动态数组被复制。

在传递字符串时使用 const 具有最佳性能,因为编译器可以优化引用计数代码。

您的 C 代码有些混乱。你不想要char**,而是想要char*。请记住,C 字符串 char* 只是指向以 null 结尾的内存块的指针。您不需要获取指向 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 C 字符串与 Delphi 字符串完全不同。在 C 中,您需要自己管理缓冲区。您可以修改 C 字符串中的字符,但如果您想要 C 中的 var s: string 等价物,那么您确实可以使用 char**。但是随后您将需要释放旧字符串并重新分配一个新字符串(如果您需要扩展它)。没有引用计数等等。我使用了char*,因为您没有进行修改。这是人们使用 C++ 而不是 C 的众多原因之一。
  • 是的,const 是最快的。不过,这很少见。
【解决方案2】:

没有人强调一个众所周知的事实,即自 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 以来变得更好),但恕我直言,这是一种安全的跨语言方式将一些 TEXT 数据导出到 Delphi 应用程序和库(在 Windows 世界中)。例如,.Net 世界会喜欢编组那些 OLESTR 类型的变量。

【讨论】:

    【解决方案3】:

    我猜代码有点误导。它是否打算只打印“FUNCTION”?如果是这样:

    void testfunction(const char *Data)
    {
        printf("Data = %s\n", Data);
        return;
    }
    
    int main()
    {
        char Data[] = "TEST FUNCTION";
        testfunction(Data+4);
        return 0;
    }
    

    这会将字符串从数组中的索引 4(包括)传递到该函数的其余部分。 通过传递 char* 您不会在该函数的本地堆栈中复制字符串。只是指向该内存开头的指针。

    【讨论】:

      【解决方案4】:

      我只能回答 delphi 部分(我的 C 刚刚有点生锈,当我 最新的时,C 指针/数组引用让我头疼)

      字符串是指针并且总是通过引用传递,所以在传递 -EVER 时不会复制数据。

      但是,在

      的情况下
      procedure test(s:String);
      

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

      procedure test(var s: String);
      

      传递指针S的地址,

      指针 S 被传递,如果您在过程测试中修改 S,则会生成一个唯一字符串(如果需要),并将新指针分配给 S,以及原始传递的变量。您永远不能传递字符串字面量和字符串表达式/即时修改 (s+'bla bla bla')

      procedure test(const s: string);
      

      指针S通过,在程序测试期间不能修改S。 (好吧,你可以搞砸并欺骗编译器,但它很难做到,而且通常需要大量的类型转换)

      【讨论】:

      • 有点复杂。即使您不修改 string.dify 字符串,普通的按值传递也会产生引用计数开销。使用 const 可以避免这种情况。
      • @David Heffernan -> 是的,我忘了他们增加了一个内存值。尽管如此,仍然比提问者认为的完整副本要少得多。
      • 嗯,是的,少于不会发生的完整副本! ;-) 如果 plain by value 和 const 之间的差异很大,我会感到震惊。
      • @David:但是,当然,将纯输入参数声明为const也有语义价值。
      • @Andreas 当然。由于问题的性质,我戴着眼罩。
      猜你喜欢
      • 1970-01-01
      • 2010-11-12
      • 1970-01-01
      • 2010-10-11
      • 1970-01-01
      • 2011-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多