【发布时间】:2014-01-05 05:58:31
【问题描述】:
pascal 字符串在内存中是如何布局的?
我读到: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.
pascal 代码正确打印长度,并且由于分配,引用计数增加了 1。这是正确的。
但是,一旦执行完毕,它就会严重崩溃!它似乎正在尝试释放字符串/堆。如果我自己调用 FreeCString,它工作得很好!我不确定发生了什么。
知道为什么会崩溃吗?
【问题讨论】:
-
您混淆了 Pascal 的多个版本(Wirth/Turbo Pascal 在字节 0 中定义长度,Delphi 2 引入长字符串之后的所有内容都不会,除非它们被声明为
ShortString)。您在标签中列出了四种不同的语言。相反,你为什么不首先解释你真正想要完成的事情,并询问如何做到这一点?它为什么崩溃是因为你对不正确的事情做出了错误的假设。 -
那里。我已经缩小了语言范围。我正在尝试将 c 样式的字符串转换为帕斯卡字符串,而不必同时将长度作为参数传递。
-
“我正在尝试将 c-stype 字符串转换为 pascal 字符串”是什么意思? Delphi/Free Pascal 可以很好地接受空终止的 C 风格字符串,而无需长度参数;它在每个单独的 Windows 应用程序中完成了数千次(通过 WinAPI 调用)。再说一遍,你到底想完成什么?
-
char* &ptr是 C++。不确定是否要重新标记问题。 -
@KenWhite 我尝试正常操作,但出现访问冲突。我也尝试过使用 PChar。这只会打印我的字符串中的第一个字符。
标签: c string freepascal