2013-12-16 2 views
1

Попытка перемещения Delphi 2007 проект XE4. В Delphi 2007 Я использовал функцию, которая считывает массив байтов из сокета напрямую с помощью Indy. Я прошел AnsiString отлиты в массив байтов в параметре вар этой функции:Использование AnsiString как байт массива в Delphi XE4

var data:AnsiString; 
AContext.Connection.IOHandler.ReadBytes(TIDBytes(Data), PacketLength-PacketLengthDelta-1, False); 

В Dlphi XE когда я пытаюсь concatinate Data на другую строку, я получил access violation ошибку.

Теперь я пытаюсь моделировать эту проблему более простой код:

TIdBytes = array of Byte; 

procedure fill(var b: TIDBytes); 
begin 
setlength(b,5); 
b[0]:=61; 
b[1]:=61; 
b[2]:=61; 
b[3]:=61; 
b[4]:=61; 

//original function used move function 
end; 



procedure TMainForm.FormCreate(Sender: TObject); 
var s: ansistring ; 
begin 
fill(TIDBytes(s)); 
Showmessage(s); 
end; 

Теперь я ожидал увидеть что-то вроде ==== в окне сообщения, но я получил пустую. Я предположил, что XE AnsiString действует так же, как Delphi 2007 Ansistring, и вы можете использовать их как массив байтов в обоих случаях.

Каков наилучший способ решить проблему с AnsiString с байтами?

ответ

5

Это никогда не было действительным, чтобы отличить AnsiString к массиву байтов. Этот код всегда был сломан, и вам повезло (или не повезло в зависимости от вашей точки зрения).

Управляемые типы строк, так же как и динамические массивы, имеют дополнительную полезную информацию, метаданные, которые хранятся непосредственно перед полезной нагрузкой данных. Эти метаданные включают количество ссылок, длину и т. Д. Но метаданные для строк не такие же, как для динамических массивов. Проще говоря, строка не является динамическим массивом. Ваш реинтерпрет полностью недействителен. Это было неверно в старых версиях Delphi, и это так же неверно в современных версиях.

Что действительно происходит под капотом, так это то, что размер метаданных изменился с введением поддержки Unicode. Расширены метаданные для AnsiString. Теперь он содержит, например, кодовую страницу строки.

Теперь, когда вы вызываете SetLength, выделяется блок памяти, достаточно большой для метаданных и полезной нагрузки. Предположим, что память выделена по адресу P. Адрес, который имеет ваша переменная (строка или динамический массив), установлен в размер P + метаданных. Когда вы приступите к освобождению объекта, система переместится в P - размер метаданных и вызовет FreeMem с этим адресом. И вот кикер. Вы используете размер метаданных динамического массива при распределении, но размер метаданных строки при освобождении. Результат? БУМ! Вы только что вызвали FreeMem по недопустимому адресу, который не был выделен вам.

Правильный способ справиться с этим - дать функции Indy то, что она хочет. А именно массив байтов. Если вам нужно передать строковую переменную, скопируйте содержимое массива байтов в новую строку. Например, используя TEncoding.Default.GetString().

+3

Или , используйте функцию 'BytesToString()' Indy'. Или лучше, используйте 'TIdIOHandler.ReadString()' вместо 'TIdIOHandler.ReadBytes()' и пусть Indy обрабатывает преобразование байтов в строку для вас. –

1

Использование процедуры заливки и ваше определение TIDBytes:

procedure Test; 
var 
    s: ansistring; 
    b: TIDBytes; 
begin 
    fill(b); 
    s := StringOf(TArray<byte>(b)); 
    ShowMessage(s); 
end; 

PS: @David ответ правильный, но вы можете использовать directy массив байтов, а затем использовать StringOf, чтобы получить строку/AnsiString

+0

Это реализация заключительного абзаца моего ответа.Это код, который делает то, что я сказал, когда писал «копировать содержимое массива байтов в новую строку». Интересно, для чего нужен вызов «ZeroMemory». –

+0

Да, я видел это после публикации ответа. Сожалею! ZeroMemory не требуется, просто привычка. Я отредактирую эту часть. –

+1

+1 Ваш код Я думаю, имеет то же значение, что и 'TEncoding.Default.GetString (TBytes (b))'. Настоящий позор, что все эти кровопускания нужны. Почему все не могут просто использовать «TArray » - это вне меня. Головы должны быть сбиты! ;-) –

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