размер строк pChar в паскале
Модератор: Модераторы
-
sacred phoenix
- незнакомец
- Сообщения: 7
- Зарегистрирован: 12.04.2007 19:20:08
размер строк pChar в паскале
Если объявить константу или переменную типа pChar, то как проще всего обратиться к ее длине? sizeof возвращает 4 - разиер указателя. Можно использовать что-нибудь вроде lstrlen, но это некрасиво и медленно. Можно конечно объявлять строку как ansistring(она тоже заканчивается нулем, как и pChar) и длину брать как length(ansistring), но это уже немного не то.
- shade
- энтузиаст
- Сообщения: 879
- Зарегистрирован: 21.02.2006 19:15:48
- Откуда: http://shamangrad.net/
- Контактная информация:
-
Replicator
- постоялец
- Сообщения: 154
- Зарегистрирован: 30.04.2006 17:14:45
- Откуда: Outer Heaven
- Контактная информация:
По-моему, самый быстрый, но не самый лучший способ - WinAPI. Если надо соблюсти кроссплатформенность, то используй что-то вроде lstrlen/length...
Там проблема в том, что единственный способ узнать фактическую длину строки - найти в этой строке символ #0, а как это сделать, если не перебором?
А вообще, ansistring, на мой взгляд, оптимальный вариант. Вычисление длины происходит практически без затрат, так как длина строки хранится по смещению -4 от адреса в указателе (по крайней мере в Delphi). А приведение типа туда-обратно происходит также очень быстро - все что надо, это "забыть" о смещении -4 и добавить в конец (адрес известен) #0, если его там нет (а если, как Вы говорите, там уже есть #0, то и этого не надо).
Там проблема в том, что единственный способ узнать фактическую длину строки - найти в этой строке символ #0, а как это сделать, если не перебором?
А вообще, ansistring, на мой взгляд, оптимальный вариант. Вычисление длины происходит практически без затрат, так как длина строки хранится по смещению -4 от адреса в указателе (по крайней мере в Delphi). А приведение типа туда-обратно происходит также очень быстро - все что надо, это "забыть" о смещении -4 и добавить в конец (адрес известен) #0, если его там нет (а если, как Вы говорите, там уже есть #0, то и этого не надо).
-
sacred phoenix
- незнакомец
- Сообщения: 7
- Зарегистрирован: 12.04.2007 19:20:08
length для переменной типа pChar компилируется в тот же поиск нулевого байта в конце(у меня FPC 2.0.4), а для типа ansistring это взятие значения на по смещению -4 относительно указателя на строку, что конечно намного быстрее. Я согласен, что это самый оптимальный путь.
Я посмотрел на приведение типов в FPC, если использовать приведение к pChar компилятор вставляет дополнительную проверку на содержание нуля в переменной; приведение к pointer этого не дает, т.е. это будет немного оптимальнее.
Я посмотрел на приведение типов в FPC, если использовать приведение к pChar компилятор вставляет дополнительную проверку на содержание нуля в переменной; приведение к pointer этого не дает, т.е. это будет немного оптимальнее.
- shade
- энтузиаст
- Сообщения: 879
- Зарегистрирован: 21.02.2006 19:15:48
- Откуда: http://shamangrad.net/
- Контактная информация:
Replicator писал(а):А приведение типа туда-обратно происходит также очень быстро - все что надо, это "забыть" о смещении -4 и добавить в конец (адрес известен) #0, если его там нет (а если, как Вы говорите, там уже есть #0, то и этого не надо).
В fpc, да и в delphi, данное приведение реализуется несколько сложнее.
Если счетчик ссылок не равен 1, то строка дублируется (т.е. выделяется память под новую строку, затем копируются символы), а затем уж забывается, что там есть длина и счетчик ссылок.
PS: нуль в конце есть ansistring поумолчанию
- Sergei I. Gorelkin
- энтузиаст
- Сообщения: 1409
- Зарегистрирован: 24.07.2005 14:40:41
- Откуда: Зеленоград
sacred phoenix писал(а): Я посмотрел на приведение типов в FPC, если использовать приведение к pChar компилятор вставляет дополнительную проверку на содержание нуля в переменной; приведение к pointer этого не дает, т.е. это будет немного оптимальнее.
Зато может рухнуть, если на вход попадется пустая строка. Пустая строка - это nil, приведение ее к PChar даст ненулевой указатель на нулевой байт, а приведение к Pointer даст nil.
- shade
- энтузиаст
- Сообщения: 879
- Зарегистрирован: 21.02.2006 19:15:48
- Откуда: http://shamangrad.net/
- Контактная информация:
shade писал(а):PS: Странно, я думал что length(nil) должна работать и возвращать 0... а она оказывается рушиться, помоему это можно считать багом.
length не предназначен для работы с PChar, для PChar предназначена strlen из модуля strings
Последний раз редактировалось STAKANOV 12.05.2007 00:37:55, всего редактировалось 3 раза.
-
sacred phoenix
- незнакомец
- Сообщения: 7
- Зарегистрирован: 12.04.2007 19:20:08
В С например можно так:
char s[]="string";
и sizeof(s) теперь значит число, полностью длину строки с нулем в конце.
В паскале похоже придется использовать ansistring, а это не так удобно, т.к. чтобы взять длину приходится читать из памяти. И, например, если писать без RTL, то ansistring неприменима
Неужели без поиска нулевого байта остается только вручную посчитать длину строки-константы?
char s[]="string";
и sizeof(s) теперь значит число, полностью длину строки с нулем в конце.
В паскале похоже придется использовать ansistring, а это не так удобно, т.к. чтобы взять длину приходится читать из памяти. И, например, если писать без RTL, то ansistring неприменима
Неужели без поиска нулевого байта остается только вручную посчитать длину строки-константы?
- shade
- энтузиаст
- Сообщения: 879
- Зарегистрирован: 21.02.2006 19:15:48
- Откуда: http://shamangrad.net/
- Контактная информация:
sacred phoenix писал(а):В С например можно так:
char s[]="string";
В данном случае имеем массив
Например в случае
char s[] = "str\0ing";
strlen(s) != sizeof(s)
да и sizeof(s) даст длину с учетом нуль символа (т.е. на 1 больше чем strlen), если я че не путаю..
В паскале тоже можно
var s: array [0..8] of char = 'string';
len := sizeof(s);
STAKANOV писал(а):length не предназначен для работы с PChar,
Но тем не менее работает, см fpc_pchar_length, который отвечает за legth(p: pchar)
shade писал(а):STAKANOV писал(а):length не предназначен для работы с PChar,
Но тем не менее работает, см fpc_pchar_length, который отвечает за legth(p: pchar)
верно, документация видно немного остает
Вот еще немного рискованный вариант:
Код: Выделить всё
const s:PChar='12346789';
const s_end:PChar='#';
var
ss:LongWord;
begin
ss:=s_end-s;
writeln(ss);
end.
Правда гарантии, что компилятор расположит в памяти две констаный друг за другом нет никакой.
-
sacred phoenix
- незнакомец
- Сообщения: 7
- Зарегистрирован: 12.04.2007 19:20:08
В паскале тоже можно
var s: array [0..8] of char = 'string';
len := sizeof(s);
но тем не менее довольно неудобно вручную пересчитывать символы в строке...хотя выходит что это лучше всего.
да и sizeof(s) даст длину с учетом нуль символа (т.е. на 1 больше чем strlen), если я че не путаю..
Да он считает и нулевой символ в конце, но если допустим использовать sizeof(s)-1 то любой компилятор увидит, что тут тоже просто число. Ну а если считать такую строку-массив константой(а такие тоже нужны часто) и не изменять ее то там никогда в середине не появится \0.
Вот еще немного рискованный вариант:
Рискованный вариант наверно будет самый удачный если писать без RTL и если учитывать то, что он рискованный
sacred phoenix писал(а):если писать без RTL
кстати, как-то обсуждалось:
http://freepascal.ru/forum/viewtopic.php?t=453
извините за оффтопик
- shade
- энтузиаст
- Сообщения: 879
- Зарегистрирован: 21.02.2006 19:15:48
- Откуда: http://shamangrad.net/
- Контактная информация:
Можно сделать так
Код: Выделить всё
type
mystr = record
len: integer;
str: pchar;
end;
const
S = 'string';
x: mystr = (len: length(S); str: S);
begin
writeln('Len: ', x.len);
writeln(x.str);
end.- shade
- энтузиаст
- Сообщения: 879
- Зарегистрирован: 21.02.2006 19:15:48
- Откуда: http://shamangrad.net/
- Контактная информация:
