2015-04-22 20 views
3

我想知道是否有可能传递一个声明类型(在这种情况下是一条记录)到我的函数。我甚至不会问是否不适用于SizeOf()函数,因为它可能需要一个类型作为参数。德尔福 - 如何传递'类型'作为参数

我正在翻译C代码,我希望尽可能地保持原代码。 C程序声明PushArray和PushStruct为宏。由于德尔福没有宏支持,我试图把它们变成功能。

我已经使用了这一点,似乎我可以使用泛型类型。 像function PushStruct<T>(Arena : Pmemory_arena; dtype : <T>)但你只能在一个OOP类型的应用程序中使用它。

function PushSize_(Arena : Pmemory_arena; Size : memory_index) : pointer; 
begin 
    Assert((Arena^.Used + Size) <= Arena^.Size); 
    Result := Arena^.Base + Arena^.Used; 
    Arena^.Used := Arena^.Used + Size; 
end; 

function PushStruct(Arena : Pmemory_arena; dtype : ?) : pointer; 
begin 
    result := PushSize_(Arena, sizeof(dtype)); 
end; 

function PushArray(Arena : Pmemory_arena; Count: uint32; dtype : ?) : pointer; 
begin 
    result := PushSize_(Arena, (Count)*sizeof(dtype)) 
end; 

下面是原来的C代码:

#define PushStruct(Arena, type) (type *)PushSize_(Arena, sizeof(type)) 
#define PushArray(Arena, Count, type) (type *)PushSize_(Arena, (Count)*sizeof(type)) 
void * 
PushSize_(memory_arena *Arena, memory_index Size) 
{ 
    Assert((Arena->Used + Size) <= Arena->Size); 
    void *Result = Arena->Base + Arena->Used; 
    Arena->Used += Size; 

    return(Result); 
} 
+0

这种事情让我心惊肉跳。无论你在翻译什么样的作业,都应该以面向对象的方式重新实现,而不是直接翻译你的C代码。如果你不需要,你为什么要继续做这个巫术指针数学?你真的很喜欢C的方式,让你在脚上打几行代码?也许你甚至不需要翻译这整个东西,只需使用不同的模式,不同的数据结构进行音译,使用真正的数据类型或对象而不是低级别的内存缓冲区破解。 –

+3

亲爱的沃伦。 我正在翻译的代码来自专门教授低级Voodoo内存缓冲区访问的教育资源。作者说,虽然他知道如何使用高阶语言,但这种低层次的东西是一种垂死的艺术,他正在教它。后来我们甚至会做一些汇编代码。所以虽然我知道你对你的评论意见不错,但在这种情况下,它不适用。 –

+0

好的。很高兴你使用你的力量而不是邪恶。 –

回答

5

C代码不传送一个类型的功能。预处理器正在扩展宏和计算大小。您可以从函数的原型中看到:

void *PushSize_(memory_arena *Arena, memory_index Size) 

由于Delphi中没有宏,因此无法安排直接翻译。就个人而言,如果是我,我不会完全匹配C代码。我会通过这个大小,让它给调用者使用SizeOf。我不认为这是一个可怕的负担。它仍然给你一些非常接近直译的东西 - 你所缺少的就是方便的宏。

如果你想使用泛型,你可以这样做,但它会要求你使用静态方法。例如:

type 
    TMyClass = class 
    class function PushSize(Arena: Pmemory_arena; Size: memory_index): Pointer; static; 
    class function PushStruct<T>(Arena: Pmemory_arena): Pointer; static; 
    end; 
.... 
class function TMyClass.PushSize(Arena: Pmemory_arena; Size: memory_index): Pointer; 
begin 
    Result := ....; 
end; 

class function TMyClass.PushStruct<T>(Arena: Pmemory_arena): Pointer; 
begin 
    Result := PushSize(Arena, SizeOf(T)); 
end; 

如果你想返回一个类型的指针应该是这样的:

type 
    TMyClass<T> = class 
    type P =^T; 
    class function PushSize(Arena: Pmemory_arena; Size: memory_index): Pointer; static; 
    class function PushStruct(Arena: Pmemory_arena): P; static; 
    end; 
.... 
class function TMyClass<T>.PushSize(Arena: Pmemory_arena; Size: memory_index): Pointer; 
begin 
    Result := ....; 
end; 

class function TMyClass<T>.PushStruct(Arena: Pmemory_arena): P; 
begin 
    Result := PushSize(Arena, SizeOf(T)); 
end; 

显然,你会知道改用什么名字的TMyClass

我不相信仿制药在这里很合适,因为我猜你想要的是尽可能直译的翻译。在这种情况下,我不会选择使用泛型。

+0

你可能是对的。你有什么想法如何sizeof工作?由于没有实际的声明,我可以在System.pas中找到,我很好奇它将如何声明。 –

+0

它是一个编译器内在的,所以没有函数的源代码,因为它在运行时没有被评估。编译器知道类型是什么,知道它的大小,并且可以在编译时评估函数。所以'SizeOf(T)'是一个常量。 –

2

你可以根据需要通过简单的声明对于每个记录类型自己推* funtions“展开宏”:

type 
    // just guessing here... 
    PMemoryArena = ^TMemoryArena; 
    TMemoryArena = record 
    Base: Pointer; 
    Used: Cardinal; 
    Size: Cardinal; 
    end; 
    TMemoryIndex = Cardinal; 
    // 1st example record type 
    PMyRecord1 = ^TMyRecord1; 
    TMyRecord1 = record 
    I1: Integer; 
    I2: Integer; 
    end; 
    // 2nd example record type 
    PMyRecord2 = ^TMyRecord2; 
    TMyRecord2 = record 
    D1: Double; 
    D2: Double; 
    end; 

function PushSize_(Arena: PMemoryArena; Size: TMemoryIndex): Pointer; inline; 
begin 
    Assert(Arena^.Used + Size <= Arena^.Size); 
    Result := Pointer(NativeUInt(Arena^.Base) + Arena^.Used); 
    Inc(Arena^.Used, Size); 
end; 

function PushMyRecord1(Arena: PMemoryArena): PMyRecord1; 
begin 
    Result := PMyRecord1(PushSize_(Arena, SizeOf(TMyRecord1))); 
end; 

function PushMyRecord2(Arena: PMemoryArena): PMyRecord2; 
begin 
    Result := PMyRecord2(PushSize_(Arena, SizeOf(TMyRecord2))); 
end; 
+0

我曾考虑过这个问题。使用函数重载将会更好,因此您可以继续使用相同的函数名称。 –

+0

好主意,但你必须使用out参数的程序,因为重载函数可能不会因返回类型而不同(不会编译)。所以你可以有如下程序:'procedure PushStruct(Arena:PMemoryArena; out Struct:PMyRecord1);超载;程序PushStruct(Arena:PMemoryArena; out Struct:PMyRecord2);超载; '等 –

+0

是的,这就是我最终实现它的方式。 –

0

它似乎那种不必要的。

为什么不,例如

function PushStruct(Arena : Pmemory_arena) : pointer; 
begin 
    result := PushSize_(Arena, sizeof(Arena)); 
end; 
+0

那么,如果你仔细观察,提问者想用不同的尺寸值进行调用。另外,你知道sizeof(Arena)只是一个指针的大小? –

+0

是的,大卫 - 我的错。 – Dsm