2015-10-16 57 views
2

如何使用可变参数打印出多个字符串?我试过这个,但我不能确定数组的大小。它只是打印垃圾。如何使用可变参数打印字符串?

program Project1; 

{$APPTYPE CONSOLE} 
{$POINTERMATH ON} 

function _Print(const S: String): string; cdecl; 
var 
    Args: Array[0..100] of Pointer absolute S; 
    I: Integer; 
begin 
    I := 0; 
    while Args[I] <> nil do 
    begin 
    WriteLn(PString(@Args[I])^); 
    Inc(I); 
    end; 
end; 

const Print: function(const S: String): string; cdecl varargs = _Print; 

var 
    A, B: String; 
begin 
    A := 'ABC'; 
    B := 'CDE'; 
    Print(a, b, 'asdasd', 'fasd', ' ') 
end. 
+0

为什么你需要做的这一切? Delphi支持数组,并且具有允许您在数组中获得'Length','Low'索引和'High'索引值的函数。你可以简单地将数组传递给你的函数并遍历它,而不用试图跳过所有这些箍。你的函数声明就变成了'procedure Print(Values:string of array);'。 –

+0

这不是*更快*。你从哪里得到这个荒谬的想法? *我更喜欢指针*是无稽之谈。对于你在这里试图做的事情,没有速度的提高,这是一个不必要的复杂程度。 (即使您删除了您在我发布此回复后立即回复的评论,但我仍然留下该评论。为了其他人的利益,它说*因为它更快,我更喜欢ponters *)。 –

回答

3

一个varargs功能没有自动化的方式来确定被传递的参数数目,因为只有在调用方知道多少个参数,它被调用堆栈上的投入。该函数必须手动确定的参数,或者通过:

  1. 要求调用者传递的参数的实际数量为固定参数:

    function _Print(NumStrings: Integer; const Strings: string): string; cdecl; 
    var 
        Args: Array[0..100] of Pointer absolute Strings; 
        I: Integer; 
    begin 
        for I := 0 to NumStrings-1 do 
        begin 
        WriteLn(PString(@Strings[I])^); 
        end; 
    end; 
    
    const 
        Print: function(NumStrings: Integer; const Strings: string): string; cdecl varargs = _Print; 
    
    var 
        A, B: String; 
    begin 
        A := 'ABC'; 
        B := 'CDE'; 
        Print(5, a, b, 'asdasd', 'fasd', ' '); 
    end. 
    
  2. 把一个岗哨值在的端部该函数可以查找的参数列表。你的功能已经被编码为这个(它正在寻找nil指针),所以只传递一个:

    Print(a, b, 'asdasd', 'fasd', ' ', nil); 
    

话虽这么说,这两种方法是受调用者的错误,因此潜在的危险,如果滥用,这就是为什么varargs型功能不经常使用。你应该考虑使用开放数组参数,而不是:

program Project1; 

{$APPTYPE CONSOLE} 
{$POINTERMATH ON} 

function _Print(const Args: array of string): string; 
var 
    I: Integer; 
begin 
    for I := Low(Args) to High(Args) do 
    begin 
    WriteLn(Args[I]); 
    end; 
end; 

const 
    Print: function(const Args: array of string): string = _Print; 

var 
    A, B: String; 
begin 
    A := 'ABC'; 
    B := 'CDE'; 
    Print([a, b, 'asdasd', 'fasd', ' ']); 
end. 
+0

这不是真的。它用于RTL。 'UStrCatN' – user15124

+1

@ user15124:我没有说他们根本没用过。我说他们不常使用。即使在RTL中也没有。另外,如果你仔细看看'UStrCatN'的实现,你会看到它有一个'ArgCnt'固定参数。编译器填充该值,因为它知道它连接在一起的多少个字符串。 –

+0

@ user15124:在RTL中,特别是在System.pas中,有一些函数在它们后面有相当多的编译器魔术。 IIRC,有些甚至比EAX,EDX,ECX有不同的参数,所以系统单元很难被看作是纯Delphi的主要例子。事实是,德尔福不(没有技巧)允许你写可变参数函数。改为使用const数组。 –