Pascal和 Delphi 数组到C/C++数组

hts6caw3  于 5个月前  发布在  C/C++
关注(0)|答案(3)|浏览(76)

在pascal和 Delphi 中,数组的长度存储在内存中数组指针的某个偏移量处。我发现下面的代码对我有用,它可以获取数组的长度:

type PInt = ^Integer; //pointer to integer.

Function Length(Arr: PInt): Integer;
var
  Ptr: PInt;
Begin
  Ptr := Arr - sizeof(Integer);
  Result := Ptr^ + 1;
End;

Function High(Arr: PInt): Integer;  //equivalent to length - 1.
Begin
  Result := (Arr - sizeof(Integer))^;
End;

字符串
我把上面的代码翻译成C++,它就变成了:

int Length(int* Arr)
{
  int* Ptr = (Arr - sizeof(int));
  return *reinterpret_cast<char*>(Ptr) + 1;
}

int High(int* Arr)
{
    return *(Arr - sizeof(int));
}


现在假设上面的是等价于Pascal/ Delphi 版本,我如何写一个结构来表示Pascal数组?
换句话说,我如何编写一个结构体,使以下内容为真:
第一个月
我尝试了以下方法:

typedef struct
{
    unsigned size;
    int* IntArray;
} PSArray;

int main()
{
    PSArray ps;
    ps.IntArray = new int[100];
    ps.size = 100;

    std::cout<<Length((int*) &ps); //should print 100 or the size member but it doesn't.

    delete[] ps.IntArray;
}

gdx19jrr

gdx19jrr1#

为什么?为什么?我看不出有什么好的理由这么做。在Pascal中使用惯用Pascal,在C中使用惯用C。像这样使用sizeof也会忽略填充,所以你的结果可能会因平台而异。
如果你想要一个大小,将其存储在结构中。如果你想要一个非成员长度函数,只需编写一个与你编写结构的方式一起工作的函数。我个人建议,如果大小不会改变,则使用std::array,如果大小会改变,则使用std::vector。如果你绝对需要一个非成员长度函数,请尝试以下操作:

template<typename T>
auto length(const T& t) -> decltype(t.size()) {
    return t.size();
}

字符串
这将适用于std::arraystd::vector
附言:如果您这样做是出于“性能原因”,请分析您的代码,并在执行将成为维护风险的操作之前证明存在瓶颈。

mftmpeh8

mftmpeh82#

在Pascal和 Delphi 中,数组的长度存储在内存中数组指针的某个偏移量处。
事实并非如此。你的问题的整个前提都是错误的。你给出的 Delphi 函数一般都不起作用。它们可能对动态数组起作用。但你可以传递一个指向数组的指针,并确保长度存储在它之前,这肯定是不可能的。
事实上,问题中的 Delphi 代码甚至不能处理动态数组。你的指针算法完全错误。你读取的值是向左16个字节,而不是4个字节。你无法检查nil。所以这真的有点像一场灾难。
接下来是C代码,你正在收获这个错误前提的结果。你已经分配了一个数组。没有理由相信数组左边的int拥有长度。你的C代码也是非常破碎的。但是尝试修复它没有什么意义,因为它永远无法修复。您定义的函数无法实现。数组存储的情况根本就不是这样与包含长度的变量相邻。
你在C++代码中寻找的是std::vector。它为获取容器的长度提供了一流的支持。不要重新发明轮子。
如果互操作是你的目标,那么你需要使用有效的互操作类型。而 Delphi 管理的动态数组不合格。使用一个指向数组的指针,和一个单独传递的长度。

bksxznpy

bksxznpy3#

上面的每一个评论都是错误的,并且仍然错误地认为Pascal和 Delphi 没有在数据之前存储数组和字符串长度。
https://github.com/fpc/FPCSource/blob/main/rtl/inc/ustrings.inc#L39https://github.com/fpc/FPCSource/blob/main/rtl/inc/ustrings.inc#L203https://github.com/fpc/FPCSource/blob/main/rtl/inc/astrings.inc#L43
数组也是如此。在 Delphi 中也是如此。我检查过了。GCC有regparm调用约定,你也可以用它来调用Pascal/ Delphi 函数。

#if defined(__GNUC__) || !defined(__clang__)
#define PASCAL_CALLING_CONVENTION __attribute__((regparm(3)))
#endif

typedef struct
{
    std::make_signed_t<std::size_t> refCount;
    std::make_signed_t<std::size_t> length;
    char data[];
} __attribute__((__packed__)) PascalArray;

template<typename T, std::size_t size>
struct __attribute__((__packed__)) FixedSizePascalArray
{
    const std::make_signed_t<std::size_t> refCount = -1;
    const std::make_signed_t<std::size_t> length = size;
    T data[size] = {0};
};

#if defined(FPC2)
typedef struct
{
    std::make_signed_t<std::size_t> refCount;
    std::make_signed_t<std::size_t> length;
    char data[];
} __attribute__((__packed__)) PascalString;
#else
    typedef struct
    {
        std::uint16_t codePage;
        std::uint16_t elementSize;
        #if defined(__x86_64__)
        std::uint32_t dummy;
        #endif // defined
        std::make_signed_t<std::size_t> refCount;
        std::make_signed_t<std::size_t> length;
        char data[];
    } __attribute__((__packed__)) PascalString;
#endif // defined

template<typename T>
T* alloc_array(std::size_t size, std::size_t element_size = sizeof(T))
{
    std::size_t new_size = (size * element_size) + sizeof(PascalArray);
    #if defined(PASCAL_CALLING_CONVENTION)
    PascalArray* ptr = AllocMem(new_size);
    #else
    PascalArray* ptr = GetMem(new_size);
    #endif
    ptr->refCount = 0;
    ptr->length = size - 1;
    return reinterpret_cast<T*>(++ptr);
}

template<typename T>
T* alloc_string(std::size_t size, std::size_t element_size = sizeof(T))
{
    std::size_t new_size = (size * element_size) + sizeof(PascalString) + sizeof(T);
    #if defined(PASCAL_CALLING_CONVENTION)
    PascalString* ptr = AllocMem(new_size);
    #else
    PascalString* ptr = GetMem(new_size);
    #endif

    ptr->refCount = 0;
    ptr->length = size;
    ptr->codePage = 65001; //CP_UTF8
    ptr->elementSize = sizeof(T);
    *reinterpret_cast<char*>(ptr + 1) = '\0';
    return reinterpret_cast<T*>(++ptr);
}

字符串
使用方法:

int* int_array = alloc_array<int>(100);
memcpy(int_array, &vector[0], vector.size() * sizeof(int));

char* str = alloc_string<char>(string.size() + 1);
memcpy(str, &string[0], string.size() * sizeof(char));


Pascal和 Delphi 都能正确地看到字符串/数组及其大小。它们也能正确地释放它们。所以不需要导出C的创建和销毁函数来操作指针。

相关问题