2014-01-05 4 views
0

Как выглядят паскальные строки в памяти?Как строки паскаля представлены в памяти?

Я читал: http://www.freepascal.org/docs-html/ref/refsu12.html В нем говорится, что строки хранятся в куче и подсчитываются ссылки. Для того, чтобы выяснить, где хранились длина и ссылок, я создал строку и сделал тесты на нем много:

type PInt = ^Integer; 

var 
    str: String; 
begin 
    str := 'hello'; 
    writeln(PInt(@str[1]) - (sizeof(integer) * 1)); //length 
    writeln(PInt(@str[1]) - (sizeof(integer) * 2)); //reference count 
end. 

Первый печатает длину и второй один печатает количество ссылок. Он делает это отлично, и он работает.

Теперь я пытался подражать то же самое в C:

Export char* NewCString() 
{ 
    const char* hello_ptr = "hello"; 

    int length = strlen(hello_ptr); 

    //allocate space on the heap for: sizeof(refcount) + sizeof(int) + strlength 
    char* pascal_string = (char*)malloc((sizeof(int) * 2) + length); 

    *((int*)&pascal_string[0]) = 0; //reference count to 0. 
    *((int*)&pascal_string[sizeof(int)]) = length; //length of the string. 

    strcpy(&pascal_string[sizeof(int) * 2], hello_ptr); //copy hello to the pascal string. 

    return &pascal_string[sizeof(int) * 2]; //return a pointer to the data. 
} 

Export void FreeCString(char* &ptr) 
{ 
    int data_offset = sizeof(int) * 2; 
    free(ptr - data_offset); 
    ptr = NULL; 
} 

Тогда в паскале я:

var 
    str: string; 
begin 
    str := string(NewCString()); 
    writeln(PInt(@str[1]) - (sizeof(integer) * 1)); //length - prints 5. correct. 
    writeln(PInt(@str[1]) - (sizeof(integer) * 2)); //reference count - prints 1! correct. 
    //FreeCString(str); //works fine if I call this.. 
end. 

Паскаля код печатает длину правильно и счетчик ссылок увеличивается на единицу из-за назначения. Это верно.

Однако, как только это будет завершено, он сильно сработает! Кажется, он пытается освободить строку/кучу. Если я сам вызываю FreeCString, он работает отлично! Я не уверен, что происходит.

Любые идеи, почему это происходит сбой?

+3

Вы вводите в заблуждение несколько версий Pascal (Wirth/Turbo Pascal определили длину в байте 0, все после появления Delphi 2 длинными строками не будет, если они не объявлены как «ShortString»). Вы указали четыре разных языка в своих тегах. Вместо этого, почему бы вам не объяснить, что вы на самом деле пытаетесь сделать в первую очередь, и спросить, как это сделать? Почему это происходит из-за того, что вы делаете ошибочные предположения о вещах, которые неверны. –

+0

Там. Я сузил языки. Я пытаюсь преобразовать строку c-style в строку pascal, не передавая также длину в качестве параметра. – Brandon

+0

Что означает «Я пытаюсь преобразовать строку c-stype в строку pascal»? Delphi/Free Pascal может принимать строки с нулевым завершенным строком C отлично, без параметра длины; это делается тысячи раз в каждом приложении Windows (с помощью сделанных вызовов WinAPI). Еще раз, что вы на самом деле пытаетесь достичь? –

ответ

0

Просто потому, что система времени выполнения выделяет строки определенным образом в памяти, не означает, что запись кода C для дублирования этого макета памяти будет работать. Управление строками может включать дополнительные ограничения или внешние структуры данных. Чтобы сделать строку совместимой с FreePascal, используйте собственные библиотечные процедуры FreePascal.

Похоже, что FreePascal требует чего-то, кроме free(), когда перерасчет идет на ноль, но, вероятно, невозможно сказать, что без какой-либо обратной инженерии или копаться в спецификациях ABI.

1
  1. "строка" является псевдонимом, который может указывать на 3-х различных типов строк (ShortString, AnsiString и UnicodeString)
  2. AnsiString и UnicodeString изменилась компоновка, идущих от FPC 2.6 до FPC 2.7.x + (равный Delphi 2007 для Delphi 2009)
  3. Любой распределитель памяти Delphi должен иметь возможность указывать размер выделенного блока. Обычно это делается путем помещения 32-битного размера в блок.
  4. FreePascal и Delphi имеют подключаемые распределители памяти. Диспетчер Free Pascal по умолчанию является собственным субаллокатором. Чтобы он использовал (на * nix) все, что использует libc, используйте unit cmem в качестве первого элемента в вашей основной программе.
  5. Как аннулирование, так и unicodestring refcounted, используя ручные трюки, за которые вы отвечаете за поддержание целостности количества ссылок. Который включает в себя поддержание Pascal ABI в этом для переходов Pascal < -> C.

Короче делать не, а редкий случай, что вы должны добавить конструктор и функцию деструктора Паскаля, и сделать все выделение с помощью этого.

P.s. вы можете захотеть взглянуть на rtl/inc/astrings.inc P.s.2 на Windows, может быть проще всего использовать совместимую с COM совместимость (BSTR) для межъязыковых типов строк.

+0

Я исправил его, изменив счетчик ссылок на -1. Создание pascal считает, что строка является постоянной. Таким образом, он никогда не пытается «освободить» мои струны, и я сам справляюсь с этим. Сейчас работает отлично. Я попробую, что ты сказал. – Brandon

Смежные вопросы