PShortString — Тип Delphi

PShortString — Тип Delphi

Пишу библиотеку.
В языке, на котором будет при программировании использоваться эта библиотека возможно передовать и принимать параметры только в shortString.
Как в delphi перевести string в shortString?

var S : String;
SS : ShortString;

не катит.
у меня вызывается в библиотеке функция, котора возвращает результат в string. Если это значение присваивать параметру моей функции типа ShortString, то возникает исключение.


> Покажи

Чего показать?
код?
Function READHEADERMAIL(var subjectmail: shortString): shortString; register;
.
msg:=tIDMessage.Create(nil);
.
Try
subjectmail:=Msg.Subject;
Except
Result:=»Error»#13″Не могу прочитать тему письма!»;
end;
.

возвращает в результат сообщение об ошибке.

В каком месте и какая ошибка ?

Угу, пишу dll.
Именно при выполнении subjectmail:=Msg.Subject; возникает ошибка, в результате чего функция возвращает значение «Error»#13″Не могу прочитать тему письма!»;

при компиляции ошибок нет

Читал что написано в коменте при создании пустого проекта DLL (ShareMem) ?

А какая всетаки ошибка ?

С этой ошибко йразобрался, теперь другая, подобная :))

Function READHEADERMAIL(var d1: shortString): shortString; register;
var ss: string;
.
msg:=tIDMessage.Create(nil);
.
Try
ss:=DateToStr(Msg.Date);
d1:=ss;
Except
on E: Exception do
begin MessageDlg(E.Message, mtInformation, [mbOk], 0);
Result:=»Error»; end;
end;
.

присвоение значения переменной ss происходит нормально, при присвоении значения переменной d1 выдает ошибку
Access violation at adress . in module «. dll». Write of adress .

И еще, по поводу первой ошибки:
результат возвращается в сабжект не весь, а только первое слово из строки, с чем может быть связано?
Пример сабжект имеет значение Test sub
в переменную subjectmail возвращается только Test

А у меня не выдает.
Уверен что при присвоении d1:=ss, а не при ss:=DateToStr(Msg.Date); ?

Как вызываем ?
FreeLibrary делаем ?

уверен, так как при коментировании d1:=ss; функция вызывается нормально.
Самое интересное, что при компиляции в делфях ошибки нет, но при вызове функции из библиотеки моей программы выдается такая ошибка.

зачем FreeLibrary ?
как вызывается из моего приложения?


> it_work © (02.05.06 09:22) [14]

Попробуй в DLL вместо ss:= DateToStr(msg.Date); поставить ss:= DateToStr(Now) у меня работает.
А отладчиком не пробовал пользоваться Run -> Attach to process

Отладчик есть для этого — прекрасно трассирует библиотеки
только не Run -> Attach to process
а
Run -> paremeters -> host application


> Попробуй в DLL вместо ss:= DateToStr(msg.Date); поставить
> ss:= DateToStr(Now) у меня работает.

Та же самая ерунда, ошибка вываливается именно при присвоении значения из ss в d1
А ты пробуешь просто в приложении или в dll?
В приложении и у меня работает :))


> it_work © (02.05.06 09:47) [17]
> А ты пробуешь просто в приложении или в dll?

function DD(var SS: ShortString): ShortString; register;
var
S: String;
begin
S:= DateToStr(Now);
SS:= s;
Result:= ss;
end;


> Отладчик есть для этого — прекрасно трассирует библиотеки
> только не Run -> Attach to process
> а
> Run -> paremeters -> host application

не все так просто, в приложении в котором используется эта библиотека своих библиотек штук 40 и все функции переплетены как черти, просто так не отладишь :( поэтому мессаги и поставил


> В DLL
>
> function DD(var SS: ShortString): ShortString; register;
>
> var
> S: String;
> begin
> S:= DateToStr(Now);
> SS:= s;
> Result:= ss;
> end;

проверяешь значение самой функции или ss при вызове функции?

Бред какой-то, когда пихаю значение в result все нормально

procedure TForm1.Button1Click(Sender: TObject);
type
TFun = function(var dd: ShortString): ShortString;
var
h: Cardinal;
p: Pointer;
t: TFun;
d: shortstring;
begin
h:= LoadLibrary(«DLL.DLL»);
p:= GetProcAddress(h,»DD»);
if p<>nil then begin
T:= P;
d:= «ggg»;
showmessage(T(d));
showmessage(d);
FreeLibrary(h);
end;
end;

Соглашения о вызовах в DLL и в приложении не попутаны, часом?

нет, так как остальные функции работают нормально и прямое присвоение значения типа d:=»11″ отрабатывает нормально


> it_work © (02.05.06 12:57) [24]

При чем тут остальные ?

Всё-таки, по тексту проверь, а не по косвенным соображениям.


> прямое присвоение значения типа d:=»11″ отрабатывает нормально

А прямое присваивание
d:=»qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq»
?

Т.к. у тебя var-параметр, проверь, имеет ли актуальный параметр достаточную длину, и не компилируется ли всё в режиме

Выставь глобально <$V+>(Project options|Compiler|Strict var-strings) и сделай build all.


> DiamondShark © (02.05.06 13:03) [27]

У него d1:= DateToStr(Msg.Date) а там от силы 10 символов.


> > прямое присвоение значения типа d:=»11″ отрабатывает
> нормально
>
> А прямое присваивание
> d:=»qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
> qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq»
> ?

у меня по тексту отправитель не длинная строка.
и ко всему моя функция возвращает результат типа ShortString, и что самое интересное присвоение result:=ss, где ss-string проходит нормально и без ошибок и возвращает правильно отправителя


> balepa © (02.05.06 13:07) [29]

А я откуда знаю, что ему реально в параметре приходит?
Он же отладчиком пользоваться отказывается, тесты не хочет выполнять, текст проверять тоже не хочет.
А телепатор, всё-таки, не казённый, батарейки к нему дорогие.


> it_work © (02.05.06 13:08) [30]

А ты попробуй, всё-таки.
Или возьми, наконец, отладчик, перед вызовом функции присвой параметру какую-нибудь характерную строку, «12345678фывапр», например, поставь в начале функции брекпоинт, и посмотри, что тебе там по ссылке передалось.

Ты понимаешь, что по симптомам — у тебя по ссылке приходит какая-то фигня. От предложенных вариантов ты отбрыкиваешься.
Как тебе ещё помочь?


> Ты понимаешь, что по симптомам — у тебя по ссылке приходит
> какая-то фигня. От предложенных вариантов ты отбрыкиваешься.
>
> Как тебе ещё помочь?

Да я понимаю и не отбрыкиваюсь, но суть, что присвоение результату функции проходит нормально, а параметру функции нет, присваивается одно и то же значение. тип результата функции и ее параметра один и тот же.

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

а с кодировками почты кто-нить может помочь?

Изменить тип из Tstring в string

06.12.2011, 14:57

Можно ли тип Collection преобразовать в тип ArrayList ?
Добрый день ! Можно ли тип Collection преобразовать в тип ArrayList .

Изменить тип «успеваемость» на string и посчитать среднее арифметическое
Переведите пжлст «успеваемость» в тип String и найти ср. арифметическое данного массива (7 цифр.

Строковый тип. Описать функцию splite(name:string:var first,last:string)
Написать функцию splite(name:string:var first,last:string), которая из параметра name, хранящего.

Какой функцией можно преобразовать тип byte в тип string и наоборот?
Вот моя проблема, у меня конченое действие будет выводить число в 10 С.С и в типе byte, а мне надо.

String Types in Delphi (Delphi For Beginners)

As with any programming language, in Delphi, variables are placeholders used to store values; they have names and data types. The data type of a variable determines how the bits representing those values are stored in the computer’s memory.

When we have a variable that will contain some array of characters, we can declare it to be of typeString.
Delphi provides a healthy assortment of string operators, functions and procedures. Before assigning a String data type to a variable, we need to thoroughly understand Delphi’s four string types.

Short String

Simply put, Short String is a counted array of (ANSII) characters, with up to 255 characters in the string. The first byte of this array stores the length of the string. Since this was the main string type in Delphi 1 (16 bit Delphi), the only reason to use Short String is for backward compatibility.
To create a ShortString type variable we use:

The s variable is a Short string variable capable of holding up to 256 characters, its memory is a statically allocated 256 bytes. Since this is usually wasteful — unlikely will your short string spread to the maximum length — second approach to using Short Strings is using subtypes of ShortString, whose maximum length is anywhere from 0 to 255.

This creates a variable called ssmall whose maximum length is 50 characters.

Note: When we assign a value to a Short String variable, the string is truncated if it exceeds the maximum length for the type. When we pass short strings to some Delphi’s string manipulating routine, they are converted to and from long string.

String / Long / Ansi

Delphi 2 brought to Object Pascal Long String type. Long string (in Delphi’s help AnsiString) represents a dynamically allocated string whose maximum length is limited only by available memory. All 32-bit Delphi versions use long strings by default. I recommend using long strings whenever you can.

The s variable can hold from zero to any practical number of characters. The string grows or shrinks as you assign new data to it.

We can use any string variable as an array of characters, the second character in s has the index 2. The following code

assigns T to the second character os the s variable. Now the few of the first characters in s look like: TTe s str. .
Don’t be mislead, you can’t use s[0] to see the length of the string, s is not ShortString.

Reference counting, copy-on-write

Since memory allocation is done by Delphi, we don’t have to worry about garbage collection. When working with Long (Ansi) Strings Delphi uses reference counting. This way string copying is actually faster for long strings than for short strings.
Reference counting, by example:

When we create string s1 variable, and assign some value to it, Delphi allocates enough memory for the string. When we copy s1 to s2, Delphi does not copy the string value in memory, it only increases the reference count and alters the s2 to point to the same memory location as s1.

To minimize copying when we pass strings to routines, Delphi uses copy-on-write technique. Suppose we are to change the value of the s2 string variable; Delphi copies the first string to a new memory location, since the change should affect only s2, not s1, and they are both pointing to the same memory location.

Илон Маск рекомендует:  Что такое код imagecreatefromxbm

Wide String

Wide strings are also dynamically allocated and managed, but they don’t use reference counting or the copy-on-write semantics. Wide strings consist of 16-bit Unicode characters.

About Unicode character sets

The ANSI character set used by Windows is a single-byte character set. Unicode stores each character in the character set in 2 bytes instead of 1. Some national languages use ideographic characters, which require more than the 256 characters supported by ANSI. With 16-bit notation we can represent 65,536 different characters. Indexing of multibyte strings is not reliable, since s[i] represents the ith byte (not necessarily the i-th character) in s.

If you must use Wide characters, you should declare a string variable to be of the WideString type and your character variable of the WideChar type. If you want to examine a wide string one character at a time, be sure to test for multibite characters. Delphi doesn’t support automatic type conversions betwwen Ansi and Wide string types.

Null terminated

A null or zero terminated string is an array of characters, indexed by an integer starting from zero. Since the array has no length indicator, Delphi uses the ASCII 0 (NULL; #0) character to mark the boundary of the string.
This means there is essentially no difference between a null-terminated string and an array[0..NumberOfChars] of type Char, where the end of the string is marked by #0.

We use null-terminated strings in Delphi when calling Windows API functions. Object Pascal lets us avoid messing arround with pointers to zero-based arrays when handling null-terminated strings by using the PChar type. Think of a PChar as being a pointer to a null-terminated string or to the array that represents one. For more info on pointers, check:Pointers in Delphi.

For example, The GetDriveType API function determines whether a disk drive is a removable, fixed, CD-ROM, RAM disk, or network drive. The following procedure lists all the drives and their types on a users computer. Place one Button and one Memo component on a form and assign an OnClick handler of a Button:

Mixing Delphi’s strings

We can freely mix all four different kinds of strings, Delphi will give it’s best to make sense of what we are trying to do. The assignment s:=p, where s is a string variable and p is a PChar expression, copies a null-terminated string into a long string.

Character types

In addition to four string data types, Delphi has three character types: Char, AnsiChar, and ​WideChar. A string constant of length 1, such as ‘T’, can denote a character value. The generic character type is Char, which is equivalent to AnsiChar. WideChar values are 16-bit characters ordered according to the Unicode character set. The first 256 Unicode characters correspond to the ANSI characters.

Типы строк в Delphi — 2020

Как и в любом языке программирования, в Delphi переменные являются заполнителями, используемыми для хранения значений; у них есть имена и типы данных. Тип данных переменной определяет, как биты, представляющие эти значения, хранятся в памяти компьютера.

Когда у нас есть переменная, которая будет содержать некоторый массив символов, мы можем объявить ее типомстрока. Delphi предоставляет полезный ассортимент строковых операторов, функций и процедур.

Перед назначением типа данных String переменной нам необходимо полностью понять четыре строковых типа Delphi.

Короткая строка

Проще говоря,Короткая строка представляет собой подсчитанный массив (ANSII) символов, содержащий до 255 символов в строке. Первый байт этого массива хранит длину строки. Так как это был основной тип строки в Delphi 1 (16-битный Delphi), единственная причина использовать Short String для обратной совместимости.Для создания переменной типа ShortString мы используем:

вар s: ShortString; s: = ‘Delphi Programming’; // S_Length: = Ord (s [0])); // который совпадает с Length (s)

s переменная — это короткая строковая переменная, способная содержать до 256 символов, ее память статически выделяется 256 байтов. Поскольку это обычно бесполезно — маловероятно, что ваша короткая строка распространится до максимальной длины — второй подход к использованию коротких строк — это использование подтипов ShortString, максимальная длина которых составляет от 0 до 255.

вар ssmall: String [50]; ssmall: = ‘Короткая строка, до 50 символов’;

Это создает переменную с именемssmall чья максимальная длина составляет 50 символов.

Примечание. Когда мы присваиваем значение переменной Short String, строка усекается, если она превышает максимальную длину для типа. Когда мы передаем короткие строки некоторой подпрограмме Delphi для управления строками, они преобразуются в и из длинной строки.

String / Long / Ansi

Delphi 2 выведен на Object PascalДлинная Строка тип. Длинная строка (в помощи Delphi AnsiString) представляет динамически размещаемую строку, максимальная длина которой ограничена только доступной памятью. Все 32-битные версии Delphi по умолчанию используют длинные строки. Я рекомендую использовать длинные строки, когда вы можете.

вар s: строка; s: = ‘Строка s может быть любого размера . ‘;

s переменная может содержать от нуля до любого практического количества символов. Строка увеличивается или уменьшается при назначении новых данных.

Мы можем использовать любую строковую переменную в качестве массива символов, второй символ вs имеет индекс 2. Следующий код

с [2]: = ‘Т’;

правопреемникиT ко второму символу илиs переменная. Теперь несколько первых персонажей вsвыглядит как:TTe s str . .Не вводите в заблуждение, вы не можете использовать s [0], чтобы увидеть длину строки,s не является ShortString.

Подсчет ссылок, копирование при записи

Поскольку выделение памяти выполняется Delphi, нам не нужно беспокоиться о сборке мусора. При работе с длинными (Ansi) строками Delphi использует подсчет ссылок. Таким образом, копирование строк на самом деле быстрее для длинных строк, чем для коротких.Подсчет ссылок, по примеру:

вар s1, s2: строка; s1: = ‘первая строка’; s2: = s1;

Когда мы создаем строкуs1 переменная, и присвоить ей некоторое значение, Delphi выделяет достаточно памяти для строки. Когда мы копируемs1 вs2Delphi не копирует строковое значение в память, он только увеличивает количество ссылок и изменяетs2 указать на ту же область памяти, что иs1.

Чтобы минимизировать копирование при передаче строк в подпрограммы, Delphi использует метод копирования при записи. Предположим, мы должны изменить значениеs2 строковая переменная; Delphi копирует первую строку в новую ячейку памяти, поскольку изменение должно повлиять только на s2, а не на s1, и они обе указывают на одну и ту же ячейку памяти.

Широкая Строка

Широкие строки также динамически распределяются и управляются, но они не используют подсчет ссылок или семантику копирования при записи. Широкие строки состоят из 16-битных символов Юникода.

О наборах символов Юникода

Набор символов ANSI, используемый Windows, является однобайтовым набором символов.

Unicode сохраняет каждый символ в наборе символов в 2 байта вместо 1. В некоторых национальных языках используются идеографические символы, для которых требуется более 256 символов, поддерживаемых ANSI. С 16-битной нотацией мы можем представить 65 536 различных символов. Индексирование многобайтовых строк не является надежным, так какс [я] представляет i-й байт (не обязательно i-й символ) вs.

Если вы должны использовать широкие символы, вы должны объявить строковую переменную типа WideString и свою символьную переменную типа WideChar. Если вы хотите проверять широкую строку по одному символу за раз, не забудьте проверить наличие многобитных символов. Delphi не поддерживает автоматическое преобразование типов между типами Ansi и Wide string.

вар s: W ;

Null прекращен

Строка с нулевым или нулевым окончанием — это массив символов, проиндексированный целым числом, начинающимся с нуля. Поскольку в массиве нет индикатора длины, Delphi использует символ ASCII 0 (NULL; # 0) для обозначения границы строки.Это означает, что по существу нет разницы между строкой с нулевым символом в конце и массивом [0..NumberOfChars] типа Char, где конец строки помечен # 0.

Мы используем строки с нулевым символом в конце в Delphi при вызове функций Windows API. Object Pascal позволяет нам избежать путаницы с указателями на нулевые массивы при обработке строк с нулевым символом в конце с использованием типа PChar. Думайте о PChar как о указателе на завершенную нулем строку или на массив, который представляет один.

Для получения дополнительной информации об указателях, проверьте: Указатели в Delphi.

Например,GetDriveType Функция API определяет, является ли дисковод съемным, фиксированным, CD-ROM, RAM-диском или сетевым диском. Следующая процедура перечисляет все диски и их типы на компьютере пользователя. Поместите один компонент Button и один Memo на форму и назначьте обработчик OnClick для кнопки:

процедура TForm1.Button1Click (Отправитель: TObject); вар Диск: чар; DriveLetter: String [4]; начать за Drive: = ‘A’ в ‘Z’ делать начать DriveLetter: = Drive + ‘: ‘; дело GetDriveType (PChar (Drive + ‘: ‘)) из DRIVE_REMOVABLE: Memo1.Lines.Add (DriveLetter + ‘Floppy Drive’); DRIVE_FIXED: Memo1.Lines.Add (DriveLetter + «Фиксированный диск»); DRIVE_REMOTE: Memo1.Lines.Add (DriveLetter + «Сетевой диск»); DRIVE_CDROM: Memo1.Lines.Add (DriveLetter + ‘CD-ROM Drive’); DRIVE_RAMDISK: Memo1.Lines.Add (DriveLetter + «RAM Disk»); конец; конец; конец;

Смешивание строк Дельфи

Мы можем свободно смешивать все четыре различных типа струн, Delphi предоставит лучшее понимание того, что мы пытаемся сделать. Присвоение s: = p, где s — строковая переменная, а p — выражение PChar, копирует строку с нулевым символом в конце в длинную строку.

Типы персонажей

В дополнение к четырем строковым типам данных в Delphi есть три символьных типа:голец, AnsiChar, а такжеWideChar, Строковая константа длиной 1, такая как ‘T’, может обозначать символьное значение. Общий тип символа — Char, что эквивалентно AnsiChar. Значения WideChar — это 16-разрядные символы, упорядоченные в соответствии с набором символов Unicode.

Первые 256 символов Unicode соответствуют символам ANSI.

3.3.1. Виды строк в Delphi

3.3.1. Виды строк в Delphi

Для работы с кодировкой ANSI в Delphi существует три вида строк: AnsiString , ShortString и PChar . Различие между ними заключается в способе хранения строки, а также выделения и освобождения памяти для нее. Зарезервированное слово string по умолчанию означает тип AnsiString , но если после нее следует число в квадратных скобках, то это означает тип ShortString , а число — ограничение по длине. Кроме того, существует опция компилятора Huge strings (управляется также директивами компилятора <$H+/->и <$LONGSTRINGS ON/OFF>, которая по умолчанию включена, но если ее выключить, то слово string станет эквивалентно ShortString ; или, что то же самое, string[255] . Эта опция введена для обратной совместимости с Turbo Pascal, в новых программах отключать ее нет нужды. Внутреннее устройство этих типов данных иллюстрирует рис. 3.2.

Илон Маск рекомендует:  Введение rfc 2068

Рис. 3.2. Устройство различных строковых типов Delphi

Наиболее просто устроен тип ShortString . Это массив символов с индексами от 0 до N, где N — число символов, указанное при объявлении переменной (в случае использования идентификатора ShortString N явно не указывается и равно 255). Нулевой элемент массива хранит текущую длину строки, которая может быть меньше или равна объявленной (эту длину мы будем далее обозначать M), элементы с индексами от 1 до M — это символы, составляющие строку. Значения элементов с индексами M+1..N не определены. Все стандартные функции для работы со строками игнорируют эти символы. В памяти такая переменная всегда занимает N+1 байтов.

Ограничения типа ShortString очевидны: на хранение длины отводится только один байт, поэтому такая строка не может содержать больше 255 символов. Кроме того, такой способ записи длины не совпадает с принятым в Windows, поэтому ShortString несовместим с системными строками.

В системе приняты так называемые нуль-терминированные строки: строка передается указателем на ее первый символ, длина строки отдельно нигде не хранится, признаком конца строки считается встретившийся в цепочке символов #0 . Длина таких строк ограничена только доступной памятью и способом адресации (т. е. в Windows теоретически это 4 294 967 295 символов). Для работы с такими строками предусмотрен тип PChar . Переменная такого типа является указателем на начало строки. В литературе нередко можно встретить утверждение, что PChar = ^Сhar , однако это неверно: тип PChar встроен в компилятор и не выводится из других типов. Это позволяет выполнять с ним операции, недопустимые для других указателей. Во-первых, если P — переменная типа PChar , то допустимо обращение к отдельным символам строки с помощью конструкции P[N] , где N — целочисленное выражение, определяющее номер символа (в отличие от типа ShortString , здесь символы нумеруются с 0, а не с 1). Во-вторых, к указателям типа PChar разрешено добавлять и вычитать целые числа, смещая указатель на соответствующее число байтов вверх или вниз (здесь речь идет только об операторах «+» и «-«; адресная арифметика с помощью процедур Inc и Dec доступна для любых типизированных указателей, а не только для PChar ).

При работе с PChar программист целиком и полностью отвечает за выделение памяти для строки и за ее освобождение. Именно это и служит основным источником ошибок у новичков: они пытаются работать с такими строками так же, как и с AnsiString , надеясь, что операции с памятью будут выполнены автоматически. Это очень грубая ошибка, способная привести к самым непредсказуемым последствиям.

Хотя программист имеет полную свободу выбора в том, как именно выделять и освобождать память для нуль-терминированных строк, в большинстве случаев самыми удобными оказываются специально предназначенные для этого функции StrNew , StrDispose и т. п. Их преимущество заключается в том, что менеджер памяти выделяет чуть больше места, чем требуется для хранения строки, и в эту дополнительную память записывается, сколько байтов было выделено. Благодаря этому функция StrDispose удаляет ровно столько памяти, сколько было выделено, даже если в середину выделенного блока был записан символ #0 , уменьшающий длину строки.

Компилятор также позволяет рассматривать статические массивы типа Char , начинающиеся с нулевого индекса, как нуль-терминированные строки. Такие массивы совместимы с типом PChar , что позволяет обойтись без использования динамической памяти при работе со строками.

Тип AnsiString объединяет достоинства типов ShortString и PChar : строки имеют фактически неограниченную длину, заботиться о выделении памяти для них не нужно, в их конец автоматически добавляется символ #0 , что делает их совместимыми с системными строками (впрочем, эта совместимость не абсолютная; как и когда можно использовать AnsiString в функциях API, мы рассматривали в разд. 1.1.13.).

Переменная типа AnsiString — это указатель на первый символ строки, как и в случае PChar . Разница в том, что перед этой строкой в память записывается дополнительная информация: длина строки и счетчик ссылок. Это позволяет компилятору генерировать код, автоматически выделяющий, перераспределявший и освобождающий память, выделяемую для строки. Работа с памятью происходит совершенно прозрачно для программиста, в большинстве случаев со строками AnsiString можно работать, вообще не задумываясь об их внутреннем устройстве. Символы в таких строках нумеруются с единицы, чтобы облегчить перенос старых программ, использовавших строки типа ShortString .

Счетчик ссылок позволяет реализовать то, что называется copy-on-demand, копирование по необходимости. Если у нас есть две переменные S1 , S2 типа AnsiString , присваивание вида S1:= S2 не приводит к копированию всей строки. Вместо этого в указатель S1 копируется значение указателя S2 , а счетчик ссылок строки увеличивается на единицу. В дальнейшем, если одну из этих строк потребуется модифицировать, она сначала будет скопирована (а счетчик ссылок оригинала, естественно, уменьшен) и только потом изменена, чтобы это не затрагивало остальные переменные.

Далее мы рассмотрим, какие проблемы могут возникнуть при использовании строк разного вида.

PShortString — Тип Delphi

>> О пользе типа shortstring при использовании WinAPI

Довольно значительное количество функций WinAPI принимают как параметры

указатель на заполняемый ими массив символов и размер этого массива, а

возвращают количество помещенных ими символов. Если мы работаем в ANSI (не

Unicode), здесь удобно пользоваться короткими строками и «убивать двух зайцев»

Автор: Павел Озерский, pavel @ insect.mail.iephb.ru, Санкт-Петербург

Copyright: собственная разработка автора (Павел Озерский)

function ClassName(hwnd: tHandle): shortstring;

byte(Result[ 0 ]) := GetClassName(hwnd, pChar(@Result[ 1 ]), 255 );

Работа со строковыми типами данных в Delphi

Строковый тип данных — один из самых часто используемых в программах тип. Действительно, без него не обходится практически ни один алгоритм. Даже программы, выполняющие исключительно математические операции, порой, написаны с использованием строковых типов данных.

Строка — это последовательность символов. В Object Pascal существует несколько строковых типов. Вот основные из них:

Для большинства целей подходит тип AnsiString (иногда называется Long String ).

Стандартные функции обработки строк:

1) Функция Length(Str: String) — возвращает длину строки (количество символов). Пример:

var
Str: String; L: Integer;
< . >
Str := ‘Hello!’ ;
L := Length(Str);

2) Функция SetLength(Str: String; NewLength: Integer) позволяет изменить длину строки. Если строка содержала большее количество символов, чем задано в функции, то «лишние» символы обрезаются. Пример:

var Str: String;
< . >
Str := ‘Hello, world!’ ;
SetLength(Str, 5);

3) Функция Pos(SubStr, Str: String) — возвращает позицию подстроки в строке. Нумерация символов начинается с единицы (1). В случае отсутствия подстроки в строке возращается 0. Пример:

var Str1, Str2: String; P: Integer;
< . >
Str1 := ‘Hi! How do you do?’ ;
Str2 := ‘do’ ;
P := Pos(Str2, Str1);

4) Функция Copy(Str: String; Start, Length: Integer) — возвращает часть строки Str, начиная с символа Start длиной Length. Ограничений на Length нет — если оно превышает количество символов от Start до конца строки, то строка будет скопирована до конца. Пример:

var Str1, Str2: String;
< . >
Str1 := ‘This is a test for Copy() function.’ ;
Str2 := Copy(Str1, 11, 4);

5) Процедура Delete(Str: String; Start, Length: Integer) — удаляет из строки Str символы, начиная с позиции Start длиной Length. Пример:

var Str1: String;
< . >
Str1 := ‘Hello, world!’ ;
Delete(Str1, 6, 7);

6) Функции UpperCase(Str: String) и LowerCase(Str: String) преобразуют строку соответственно в верхний и нижний регистры:

var Str1, Str2, Str3: String;
< . >
Str1 := ‘hELLo’ ;
Str2 := UpperCase(Str1); < Str2 = "HELLO" >
Str3 := LowerCase(Str1);

Строки можно сравнивать друг с другом стандартным способом:

var Str1, Str2, Str3: String; B1, B2: Boolean;
< . >
Str1 := ‘123’ ;
Str2 := ‘456’ ;
Str3 := ‘123’ ;
B1 := (Str1 = Str2); < B1 = False >
B2 := (Str1 = Str3);

Если строки полностью идентичны, логическое выражение станет равным True.

Дополнительные функции обработки строк:

В модуле StrUtils.pas содержатся полезные функции для обработки строковых переменных. Чтобы подключить этот модуль к программе, нужно добавить его имя ( StrUtils ) в раздел Uses .

1) PosEx(SubStr, Str: String; Offset: Integer) — функция аналогична функции Pos() , но позволяет задать отступ от начала строки для поиска. Если значение Offset задано (оно не является обязательным), то поиск начинается с символа Offset в строке. Если Offset больше длины строки Str, то функция возратит 0. Также 0 возвращается, если подстрока не найдена в строке. Пример:

uses StrUtils;
< . >
var Str1, Str2: String; P1, P2: Integer;
< . >
Str1 := ‘Hello! How do you do?’ ;
Str2 := ‘do’ ;
P1 := PosEx(Str2, Str1, 1); < P1 = 12 >
P2 := PosEx(Str2, Str1, 15);

2) Функция AnsiReplaceStr(Str, FromText, ToText: String) — производит замену выражения FromText на выражение ToText в строке Str. Поиск осуществляется с учётом регистра символов. Следует учитывать, что функция НЕ изменяет самой строки Str, а только возвращает строку с произведёнными заменами. Пример:

uses StrUtils;
< . >
var Str1, Str2, Str3, Str4: String;
< . >
Str1 := ‘ABCabcAaBbCc’ ;
Str2 := ‘abc’ ;
Str3 := ‘123’ ;
Str4 := AnsiReplaceStr(Str1, Str2, Str3);

3) Функция AnsiReplaceText(Str, FromText, ToText: String) — выполняет то же самое действие, что и AnsiReplaceStr(), но с одним исключением — замена производится без учёта регистра. Пример:

uses StrUtils;
< . >
var Str1, Str2, Str3, Str4: String;
< . >
Str1 := ‘ABCabcAaBbCc’ ;
Str2 := ‘abc’ ;
Str3 := ‘123’ ;
Str4 := AnsiReplaceText(Str1, Str2, Str3);

4) Функция DupeString(Str: String; Count: Integer) — возвращает строку, образовавшуюся из строки Str её копированием Count раз. Пример:

uses StrUtils;
< . >
var Str1, Str2: String;
< . >
Str1 := ‘123’ ;
Str2 := DupeString(Str1, 5);

5) Функции ReverseString(Str: String) и AnsiReverseString(Str: AnsiString) — инвертируют строку, т.е. располагают её символы в обратном порядке. Пример:

uses StrUtils;
< . >
var Str1: String;
< . >
Str1 := ‘0123456789’ ;
Str1 := ReverseString(Str1);

6) Функция IfThen(Value: Boolean; ATrue, AFalse: String) — возвращает строку ATrue, если Value = True и строку AFalse если Value = False. Параметр AFalse является необязательным — в случае его отсутствия возвращается пустая строка.

uses StrUtils;
< . >
var Str1, Str2: String;
< . >
Str1 := IfThen(True, ‘Yes’ ); < Str1 = "Yes" >
Str2 := IfThen(False, ‘Yes’ , ‘No’ );

Мы рассмотрели функции, позволяющие выполнять со строками практически любые манипуляции. Как правило, вместо строки с указанным типом данных, можно использовать и другой тип — всё воспринимается одинаково. Но иногда требуются преобразования. Например, многие методы компонент требуют параметр типа PChar , получить который можно из обычного типа String функцией PChar(Str: String) :

uses ShellAPI;
< . >
var FileName: String;
< . >
FileName := ‘C:\WINDOWS\notepad.exe’ ;
ShellExecute(0, ‘open’ , PChar(FileName), » , » , SW_SHOWNORMAL);

Тип Char представляет собой один-единственный символ. Работать с ним можно как и со строковым типом. Для работы с символами также существует несколько функций:

Chr(Code: Byte) — возвращает символ с указанным кодом (по стандарту ASCII):

Ord(X: Ordinal) — возвращает код указанного символа, т.е. выполняет противоположное действие функции Chr() :

var X: Integer;
< . >
X := Ord( ‘F’ );

Из строки можно получить любой её символ — следует рассматривать строку как массив. Например:

var Str, S: String; P: Char;
< . >
Str := ‘Hello!’ ;
S := Str[2]; < S = "e" >
P := Str[5];

Илон Маск рекомендует:  Функции bios int 1bh прерывание с клавиатуры

В этой статье описаны основные приёмы работы со строковыми типами данных. Как правило, этих данных достаточно для написания любого алгоритма.

Ссылки по теме

Популярные статьи
Информационная безопасность Microsoft Офисное ПО Антивирусное ПО и защита от спама Eset Software


Бестселлеры
Курсы обучения «Atlassian JIRA — система управления проектами и задачами на предприятии»
Microsoft Office 365 для Дома 32-bit/x64. 5 ПК/Mac + 5 Планшетов + 5 Телефонов. Подписка на 1 год. Электронный ключ
Microsoft Windows 10 Профессиональная 32-bit/64-bit. Все языки. Электронный ключ
Microsoft Office для Дома и Учебы 2020. Все языки. Электронный ключ
Курс «Oracle. Программирование на SQL и PL/SQL»
Курс «Основы TOGAF® 9»
Microsoft Windows Professional 10 Sngl OLP 1 License No Level Legalization GetGenuine wCOA (FQC-09481)
Microsoft Office 365 Персональный 32-bit/x64. 1 ПК/MAC + 1 Планшет + 1 Телефон. Все языки. Подписка на 1 год. Электронный ключ
Windows Server 2020 Standard
Курс «Нотация BPMN 2.0. Ее использование для моделирования бизнес-процессов и их регламентации»
Антивирус ESET NOD32 Antivirus Business Edition
Corel CorelDRAW Home & Student Suite X8

О нас
Интернет-магазин ITShop.ru предлагает широкий спектр услуг информационных технологий и ПО.

На протяжении многих лет интернет-магазин предлагает товары и услуги, ориентированные на бизнес-пользователей и специалистов по информационным технологиям.

Хорошие отзывы постоянных клиентов и высокий уровень специалистов позволяет получить наивысший результат при совместной работе.

Delphi Unicode String Тип, хранящийся непосредственно по его адресу (или «Unicode ShortString»)

Мне нужен строковый тип Unicode, который хранит строку непосредственно по адресу переменной, как в случае с типом ShortString (только для Ansi).

Я имею в виду, что если я объявлю S: ShortString и позволю S := ‘My String’ , то в @S я найду длину строки (как один байт, поэтому строка не может содержать более 255 символов) с последующим самой строкой в кодировке ANSI.

То, что я хотел бы, является вариантом этого Unicode. То есть я хочу, чтобы строковый тип был таким, чтобы в @S я нашел 32-разрядное целое число без знака (или на самом деле было бы достаточно одного байта), содержащее длину строки в байтах (или в символах, что половину числа байтов) с последующим представлением строки в Unicode. Я пробовал WideString , UnicodeString и RawByteString , но все они появляются только для хранения адреса в @S и реальной строки где-то еще (я думаю, что это имеет отношение к подсчету ссылок и тому подобное). Обновление: наиболее важной причиной этого является то, что было бы очень проблематично, если бы sizeof (строка) была переменной.

Я подозреваю, что нет встроенного типа для использования, и что я должен придумать свой собственный способ хранения текста так, как я хочу (что на самом деле весело). Я прав?

Обновление Мне, помимо всего прочего, нужно будет использовать эти строки в упакованных записях. Мне также нужно вручную читать / записывать эти строки в файлы / кучу. Я мог бы жить со строками фиксированного размера, такими как string delphi memory unicode

5 ответов

Ты прав. Нет точного аналога ShortString который содержит символы Unicode. Есть много вещей, которые подходят близко, в том числе WideString , UnicodeString и массивы WideChar , но если вы не желаете вернуться к тому, как вы собираетесь использовать тип данных (делать побайтные копии в памяти и в файлах хотя все еще используется их во всех контекстах, строка может быть разрешена), тогда ни один из встроенных типов Delphi не будет работать для вас.

Сбой WideString потому что вы настаиваете на том, что длина строки должна существовать по адресу строковой переменной, но WideString является ссылочным типом; единственное, что по его адресу, это другой адрес. Его длина находится по адресу , указанному в переменной, минус четыре. Однако это может измениться, потому что все операции этого типа должны проходить через API.

UnicodeString завершается ошибкой по той же причине, а также потому, что это тип с подсчетом ссылок; создание побайтной копии одного нарушает подсчет ссылок, так что вы получите утечки памяти, недопустимые операции с неверными указателями или более тонкое повреждение кучи.

Массив WideChar можно скопировать без проблем, но он не отслеживает его эффективную длину и не очень часто действует как строка. Вы можете назначить ему строковые литералы, и он будет действовать так же, как вы вызвали StrLCopy , но вы не можете назначить ему строковые переменные .

Вы можете определить запись, которая имеет поле для длины и другое поле для символьного массива. Это решило бы проблему длины, но все равно имело бы все остальные недостатки недекорированного массива.

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

Типы данных Delphi

Теперь обсудим типы данных Delphi, которые программист использует при написании программы. Любая программа на Delphi может содержать данные многих типов:

  • целые и дробные числа,
  • символы,
  • строки символов,
  • логические величины.

Целый тип Delphi

Библиотека языка Delphi включает в себя 7 целых типов данных: Shortint, Smallint, Longint, Int64, Byte, Word, Longword, характеристики которых приведены в таблице ниже.

Вещественный тип Delphi

Кроме того, в поддержку языка Delphi входят 6 различных вещественных типов (Real68, Single, Double, Extended, Comp, Currency), которые отличаются друг от друга, прежде всего, по диапазону допустимых значений, по количеству значащих цифр, по количеству байт, которые необходимы для хранения некоторых данных в памяти ПК (характеристики вещественных типов приведены ниже). Также в состав библиотеки языка Delphi входит и наиболее универсальный вещественный тип — тип Real, эквивалентный Double.

Символьный тип Delphi

Кроме числовых типов, язык Delphi располагает двумя символьными типами:

Тип Ansichar — символы c кодировкой ANSI, им ставятся в соответствие числа от 0 до 255;

Тип Widechar — символы с кодировкой Unicode, им ставятся в соответствие числа от 0 до 65 535.

Строковый тип Delphi

Строковый тип в Delphi обозначается идентификатором string. В языке Delphi представлены три строковых типа:

Тип Shortstring — присущ статически размещаемым в памяти ПК строкам, длина которых изменяется в диапазоне от 0 до 255 символов;

Тип Longstring — этим типом обладают динамически размещаемые в памяти ПК строки с длиной, ограниченной лишь объемом свободной памяти;

Тип WideString — тип данных, использующийся для того, чтобы держать необходимую последовательность Интернациональный символов, подобно целым предложениям. Всякий символ строки, имеющей тип WideString, представляет собой Unicode-символ. В отличие от типа Shortstring, тип WideString является указателем, который ссылается на переменные.

Логический тип Delphi

Логический тип соответствует переменным, которые могут принять лишь одно из двух значений: true, false. В языке Delphi логические величины обладают типом Boolean. Вам были представлены основные типы данных Delphi. Движемся дальше.

STRINGTABLE и работа с идентификаторами языков в Delphi.

Помнится в прошлом (теперь уже) году публиковал я статью-обзор «23 решения для локализации и интернационализации приложений» в котором я рассмотрел различные инструменты для перевода интерфейса приложения на разные языки. Сегодня же речь пойдет про старый, заезженный всеми кому не лень способ локализации/интернационализации приложений — с использованием ресурса STRINGTABLE. Казалось бы, про STRINGTABLE уже рассказано все, что только можно и практически на каждом более менее крупном форуме по программированию можно встретить десятки топиков с примерами по использованию такой функции как LoadString() и ей подобных. Что ещё можно добавить по использованию этого ресурса? Как оказалось — добавить есть что.

Типичный пример использования STRINGTABLE

Итак, чему нас учат на форумах при работе со STRINGTABLE? Вот самый типичнейший пример использования ресурсов для локализации приложения: 1. Создаем ресурсный файл, например, такой

2. Подключаем этот файл в проекте:

3. Таскаем строки из ресурса:

4. Радуемся — все работает, все классно и вроде бы удобно. А теперь представим, что строк у нас будет не пять, а скажем 1000 и перевести нам нашу программку надо не на 2 языка, а на 20 и при этом учесть всякие там диалекты, письмо справа-налево и всё такое прочее. Очевидно, что получившийся ресурсный файл будет, мягко говоря, не совсем удобным в использовании. С примерно похожей задачей пришлось и мне недавно столкнуться. Языков пока, конечно, не 20, а всего 10, но строк примерно под 1000 и список языков содержит китайский, корейский, арабский и прочие. Каким «макаром» все это дело красиво и удобно упаковать да так, чтобы в любой момент можно было быстро вносить коррективы в нужные строки? Полез в MSDN в поисках решения.

Что говорит MSDN?

И обнаружил довольно занятную статью под названием «STRINGTABLE resource (Windows)«. Там, конечно, тоже посылают изучать функцию LoadString(), но в этой статье кратко и толково рассказано именно про запись STRINGTABLE. Первый вариант записи STRINGTABLE полностью совпадает с рассмотренным выше примером — все строки лежат в одной большой куче, каждая строка имеет свой уникальный ID. Однако же никто нам не запрещает записать те же самые строки так:

А также размещать эти STRINGTABLE в разных res-файлах. Конечно, вариант, в котором у строк пересекаются идентификаторы создает проблемку — LoadString() уже просто так не используешь, но и это дело можно поправить, если залезть в работу со STRINGTABLE немного по-глубже (об этом поговорим чуть ниже). Как эти знания можно использовать на практике? Тут, конечно, все зависит от конкретных потребностей, но можно предложить такой вариант работы:

  1. В проекте держим отдельный pas-файл со всеми строками для локализации. Этот файл всегда содержит самые свежие варианты строк. Тут же можно определить и, например, константы с идентификаторами. Этот файл содержит строки на языке по умолчанию, например, на русском
  2. Для всех остальных языков создается по отдельному STRINGTABLE в котором определена секция LANGUAGE.
  3. По необходимости цепляем к проекту нужный res-файл (или несколькоres-файлов) и ищем строки по двум параметрам — ID и Язык.

Теперь посмотрим как этот простой алгоритм можно реализовать в Delphi. Если есть необходимость записывать RC-файл автоматически на основании каких-либо данных, то, наверняка может возникнуть вопрос по записи LANGUAGE — где брать параметры для этой секции. С этого и начнем.

Идентификаторы языков в Windows

На том же MSDN есть замечательная табличка «Language >

Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL