The stars so gaily glistened... (Mon, 19 Jan 2004 08:53:00 GMT @411)
...while the fading voice of Alex.Che whispered through the darkness:
AC> CharToOem(PSrc, PDst: PChar);
Вообще то надо знать API, хотя бы в основном
Но кроме API, чтобы не кастить к PChar и не выделять буферы руками, есть
обертки, например
Jedi Code Library: jclStrings.pas
function StrOemToAnsi(const S: AnsiString): AnsiString;
function StrAnsiToOem(const S: AnsiString): AnsiString;
RxLib: rxStrUtils.pas
function StrToOem(const AnsiStr: string): string;
{ StrToOem translates a string from the Windows character set into the
OEM character set. }function OemToAnsiStr(const OemStr: string): string;
{ OemToAnsiStr translates a string from the OEM character set into the
Windows character set. }
Привет, Leonid!
Вы пишешь 19 января 2004:
A>> Но кроме API, чтобы не кастить к PChar и не выделять буферы руками, есть
LT> Eс-но, не к PChar приводить надо, а к Pointer.
Это ещё для зачем?
var
Src, Dst: string;
begin
SetLength(Dst, Length(Src));
CharToOem(PChar(Src), PChar(Dst));
...
end;
Здравствуйте, Alex.Che, Вы писали:
A>> Но кроме API, чтобы не кастить к PChar и не выделять буферы руками, есть
LT>> Eс-но, не к PChar приводить надо, а к Pointer.
Привет, Leonid!
Вы пишешь 19 января 2004:
A>>> Но кроме API, чтобы не кастить к PChar и не выделять буферы руками, есть
LT>>> Eс-но, не к PChar приводить надо, а к Pointer.
LT> Для Src = ''
Аааа...
Об этом я как-то и не подумал
Но можно же и if'ом сей момент отловить.
Привет, Slicer!
Вы пишешь 19 января 2004:
SM> А какие проблемы? Получится указатель на строку '\0'...
Фишка в том, что когда Src = '', то вызов SetLength(Dst, Length(Src));
памяти под результирующий буфер не выделит.
Т.е. она поставит 0-му (служебному) символу паскальной строки значение 0 и всё.
Для C-шной же строки, нужен ещё завершающий 0.
А вот под него то место и не будет аллокировано!
Только на РСДН помимо ответа на вопрос, можно получить еще список орфографических ошибок и узнать что-то новое из грамматики английского языка (c) http://www.rsdn.ru/forum/cpp/4720035.1.aspx
Здравствуйте, Alex.Che, Вы писали: AC>Фишка в том, что когда Src = '', то вызов SetLength(Dst, Length(Src)); AC>памяти под результирующий буфер не выделит. AC>Т.е. она поставит 0-му (служебному) символу паскальной строки значение 0 и всё. AC>Для C-шной же строки, нужен ещё завершающий 0. AC>А вот под него то место и не будет аллокировано!
Ты уверен?
... << RSDN@Home 1.1.2 beta 3 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Что-то ты не то говоришь. У ANSI-строк (а только для них и возможно преобразование в pchar) нет нулевого символа. Зато есть терминатор.
Под дельфями проверить не могу, но под FPC 1.0.10 пишем
setlength(s,0);
writeln(integer(pchar(s)));
и получаем какое-то ненулевое значение (я боялся, что получится nil — хотя, если подумать, какого черта? ). А значит, строка распределена. А значит, есть терминатор.
Где проблема?
Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Здравствуйте, Slicer [Mirkwood], Вы писали:
SM>Но по другому хелпу D6 и кастинг к pointer тоже для пустой строки дает nil, так что это не решение.
Скорее всего, дело в самой CharToOem, т.е., она, IMHO, логично считает, что nil на входе не стоит работы (не соображу, как интерпретировать LPCTSTR, т.е., чем отличается constant от иного).
Ну, а, чтобы не ломать особо голову, лучше, все же, как говорил Алекс, проверять длину.
По поводу PChar(s) могу лишь заметить, что {Delphi help. Long string types}
When a long string variable is empty (contains a zero-length string), the string pointer is nil and no dynamic memory is associated with the string variable.
Да-да, сам уже видел. А проверьте кто-нибудь, пожалуйста: после SetLength(s,0) строка явно будет пустая, но память случайно не будет выделена? Если, как должно быть по справке, не будет, то мы нашли погрешность в эмуляции FPC действий Delphi.
Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Здравствуйте, Alex.Che, Вы писали: AC>Т.е. она поставит 0-му (служебному) символу паскальной строки значение 0 и всё. AC>Для C-шной же строки, нужен ещё завершающий 0. AC>А вот под него то место и не будет аллокировано!
Это ты наверное про шортстринг???
При SetLength помоему выделяется память с отрицательным смещением TUsed и длина строки=0 и в позицию куда указывает строка прописывается 0, т.к. строки в Delphi нулл терминированы.
и солнце б утром не вставало, когда бы не было меня
"Slicer [Mirkwood]" <16916@news.rsdn.ru> сообщил/сообщила в новостях
следующее: news:511211@news.rsdn.ru...
> Да-да, сам уже видел. А проверьте кто-нибудь, пожалуйста: после >
SetLength(s,0) строка явно будет пустая, но память случайно не > будет
выделена? Если, как должно быть по справке, не будет, > то мы нашли погрешность в эмуляции FPC действий Delphi.
Ситуация следущия, если мы имеет пустую строку, то значения указателя равно
NIL, при использовании функции PChar, для таких строк будет возвращена
внутрення пустая строка, строка, которая заканчивается символом #0. Желающии
могут проверить по исходным кодам.
На первый взгляд тут все в порядке, но только на первый взгляд.
Дело в том, что данная строка расположена в программной памяти с атрибутом
только чтение. А вот функция OemToChar и ее пара будет пытаться записать в
результат и произойдет ошибка AV.
Поэтому чтобы этого не было функцию надо вызывать так:
if S <> '' then OemToChar(PChar(S),PChar(S));
Нет никакого смысла пытаться преобразовывать пустую строку!
"solos" <6374@news.rsdn.ru> сообщил/сообщила в новостях следующее: news:510607@news.rsdn.ru...
> Нет ли такой быстрой и простой функциия для преобразования строки из
Win-1251 в DOS-866?
Так как речь идет об преобразовании 1251 в 866, то советы которые даны ниже
изначально неверны, работать будет только если локализации машины совпадает
с данными кодировками и будет неприятный удар на других машинах, функции
OemToChar/CharToOem предназначены только для совместных преобразований
кодировок OEM(DOS) — ANSI(Win), а не конкретных.
Самый быстрый путь это преобразование по таблицы, приводить его не буду,
посколько гораздо полезнее будет сходить на мой сайт и взять готовую
реализацию универсального преобразователя с некоторыми готовыми таблицами
перекодировок.
The stars so gaily glistened... (Mon, 19 Jan 2004 12:08:09 GMT @547)
...while the fading voice of Alex.Che whispered through the darkness:
AC> Проверь сам отладчиком.
Неужели компилятор такой тупаой и typecast делает так криво?
Вообще конечно забавно, есть константа EmptyStr — и не используется.
-- WinAMP://Track 6 http://Arioch.nm.ru/FL/Fidolook_SL.png Mail: the_Arioch<at>nm<dot>ru
AP>Так как речь идет об преобразовании 1251 в 866, то советы которые даны ниже AP>изначально неверны, работать будет только если локализации машины совпадает AP>с данными кодировками и будет неприятный удар на других машинах, функции AP>OemToChar/CharToOem предназначены только для совместных преобразований AP>кодировок OEM(DOS) — ANSI(Win), а не конкретных.
Ну спасибо, что хоть кто-то понял вопрос, который был именно о локализации клиентской машины. Так что апишный СharToOEM() мне знаком, но отрабатывает как хотелось бы далеко не всегда
Здравствуйте, Slicer [Mirkwood], Вы писали:
SM>Да-да, сам уже видел. А проверьте кто-нибудь, пожалуйста: после SetLength(s,0) строка явно будет пустая, но память случайно не будет выделена? Если, как должно быть по справке, не будет, то мы нашли погрешность в эмуляции FPC действий Delphi.
Не знаю насчет погрешностей, но пустая строка вполне соответствует дельфийскому
хелпу (по-крайней мере, на моей D3).
Если по порядку,
A long string variable occupies four bytes of memory which contain a pointer to a dynamically-allocated string.
Мы также знаем, что распределяемый для строки блок предваряется такой структурой
(system.pas)
type
StrRec = record
allocSiz: Longint;
refCnt: Longint;
length: Longint;
end;
Пусть объявлена s: String.
Если s <> '', то Pointer(s) указывает на первый байт (символа) строки.
Мы можем даже посмотреть значения полей StrRec:
var
p: ^StrRec;
..
s := 'x';
p := Pointer(Longint(s) - SizeOf(StrRec));
with p^ do
Caption := Format('%d %d %d %s',[allocsiz, refcnt, length, Pointer(s)]);
Однако, для пустой строки (в т.ч., после SetLength(s,0)), Pointer(s) будет содержать nil, что, собс-но, и было прописано в хелпе. Кроме того, ясно, для пустой строки не существует ни одного динамически распределенного байта (а уж тем более nil-a).
The stars so gaily glistened... (Mon, 19 Jan 2004 16:27:50 GMT @727)
...while the fading voice of Anatoly whispered through the darkness:
AP> атрибутом только чтение. А вот функция OemToChar и ее пара будет AP> пытаться записать в результат и произойдет ошибка AV.
А точно будут пытаться? что им записывать-то? строка то нулевой длины?
for i:=1 to 0 do str[i]:=..... — ни одной итерации.
Здравствуйте, Slicer [Mirkwood], Вы писали:
SM>Ну блин так ведь только что писалось, что pointer(s) хоть и должно быть nil, а все-таки не nil.
Я, наверное, чего-то пропустил, но я ни разу не усомнился, что pointer(s) для пустой строки есть nil (или, словами хелпа: "the string pointer is nil").
Возможно, тебя смутило то, что я говоря по поводу PChar привел цитату для pointer, но, я рассчитывал на то, что эта разница очевидна, бо начался разговор именно с того, что "It is also possible to typecast a long string to an untyped pointer, using the syntax Pointer(S), where S is a long string expression. A Pointer typecast returns the address of the first character of the long string value. Unlike a PChar typecast, a Pointer typecast returns nil if the string expression is empty."
Ну, и, видимо, я прав в том, что тот кто ждет LPCSTR,LPSTR понимает пустую строку как nil, а не как PChar(пустая строка). Т.е., правильно — Pointer(s)
Здравствуйте, Leonid Troyanovsky, Вы писали:
LT>Здравствуйте, Slicer [Mirkwood], Вы писали:
SM>>Ну блин так ведь только что писалось, что pointer(s) хоть и должно быть nil, а все-таки не nil.
LT> Я, наверное, чего-то пропустил, но я ни разу не усомнился, что pointer(s) для пустой строки есть nil (или, словами хелпа: "the string pointer is nil").
Лучше смотреть исходники
procedure _LStrClr(var S);
{$IFDEF PUREPASCAL}
var
P: PStrRec;
begin
if Pointer(S) <> nil then
begin
P := Pointer(Integer(S) — Sizeof(StrRec));
Pointer(S) := nil;
if P.refCnt > 0 then
if InterlockedDecrement(P.refCnt) = 0 then
FreeMem(P);
end;
end;
По уму нужно конечно делать ссылку на пустую строку EmptyString.
и солнце б утром не вставало, когда бы не было меня
S>procedure _LStrClr(var S); S>{$IFDEF PUREPASCAL} S>var S> P: PStrRec; S>begin S> if Pointer(S) <> nil then S> begin S> P := Pointer(Integer(S) — Sizeof(StrRec)); S> Pointer(S) := nil; S> if P.refCnt > 0 then S> if InterlockedDecrement(P.refCnt) = 0 then S> FreeMem(P); S> end; S>end;
S> По уму нужно конечно делать ссылку на пустую строку EmptyString.
И для приведения к Pchar
function _LStrToPChar(const s: AnsiString): PChar;
{$IFDEF PUREPASCAL}
const
EmptyString = '';
begin
if Pointer(s) = nil then
Result := EmptyString
else
Result := Pointer(s);
end;
и солнце б утром не вставало, когда бы не было меня
function _NewAnsiString(length: Longint): Pointer;
{$IFDEF PUREPASCAL}
var
P: PStrRec;
begin
Result := nil;
if length <= 0 then Exit;
// Alloc an extra null for strings with even length. This has no actual cost
// since the allocator will round up the request to an even size anyway.
// All widestring allocations have even length, and need a double null terminator.
GetMem(P, length + sizeof(StrRec) + 1 + ((length + 1) and 1));
Result := Pointer(Integer(P) + sizeof(StrRec));
P.length := length;
P.refcnt := 1;
PWideChar(Result)[length div 2] := #0; // length guaranteed >= 2
end;
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
SM>>>Ну блин так ведь только что писалось, что pointer(s) хоть и должно быть nil, а все-таки не nil.
LT>> Я, наверное, чего-то пропустил, но я ни разу не усомнился, что pointer(s) для пустой строки есть nil (или, словами хелпа: "the string pointer is nil").
S>Лучше смотреть исходники
S>procedure _LStrClr(var S);
Ну, более интересно было б смотреть CharToOEM
S> По уму нужно конечно делать ссылку на пустую строку EmptyString.
Сделано все так, как документировано.
Если хочется ссылку на пустую строку, есть PChar.
Вот это я понимаю. Но это противоречит хелпу! Там явно сказано, что приведение string->pchar для пустой строки возвращает nil. Вот это-то противоречие я и пытаюсь до вас донести.
Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Здравствуйте, Leonid Troyanovsky, Вы писали: LT> Сделано все так, как документировано.
Да нет же!
Delphi 6 Programmer's Guide (del6prog.hlp), топик "strings, declaring and initializing":
Declaring and initializing strings
...
Similarly, if you cast an empty string to a PChar, the result is a nil pointer. So, if you are passing such a PChar to a routine that needs to read or write to it, be sure that the routine can handle nil
...
Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Ну спасибо, что хоть кто-то понял вопрос, который был именно о локализации клиентской машины. Так что апишный СharToOEM() мне знаком, но отрабатывает как хотелось бы далеко не всегда
Спасибо 2 Anatoly Podgoretsky за понимание
Остальное обсуждение не менее полезно
AP> атрибутом только чтение. А вот функция OemToChar и ее пара будет AP> пытаться записать в результат и произойдет ошибка AV.
> А точно будут пытаться? что им записывать-то? строка то нулевой длины?
Будет пытаться записать завершающий 0
Легче всего это проверить если вызвать для пустой строки
AP> Ну блин так ведь только что писалось, что pointer(s) хоть и должно быть nil, а все-таки не nil.
AP>S := ''; AP>Pointer(S) -> NIL AP>PChar(S) -> EmptyStr
AP>Первое нормально документировано, по второму не нашел информации в справке.
Ну, более интересно было б смотреть CharToOEM
Чего захотел
Но в принципе и так понятно, что идет проход по строке и преобразование символов по таблице, по окончанию прохода в рельтат пишется завершающий 0, за исключения случая когда указатель равет NIL
Помнится это именно ты в свое время указал на возможную проблему при использовании функции PChar и предложил заменить ее на Pointer(S), дело было в Фидо. Это тогда послужило поводом для иследования поведения при приведении к PChar
Недавно в конференции Борланд basm обсуждалась обратная проблема, безопасно ли передавать NIL в функции работы со строками, пришли к выводу, что практически все ошибки этого рода исправили в RTL, а Windows вроде бы правильно работает как для nil так и для пустой строки (указатель на #0)/
На этот раз и данная дискуссия оказалась не менее плодотворной.
"Slicer [Mirkwood]" <16916@news.rsdn.ru> сообщил/сообщила в новостях следующее: news:512710@news.rsdn.ru...
Вот это я понимаю. Но это противоречит хелпу! Там явно сказано, что приведение string->pchar для пустой строки возвращает nil. Вот это-то противоречие я и пытаюсь до вас донести.
Я попытался найти в справке такое указание, но не смог, но зато нашел другое — при приведении пустых строк с помощью приведения к нетипизированому указателю Pointer(S) — But if S is empty, the typecast returns nil. Намек на различие с PChar, и это все, что я нашел
Delphi 6 Programmer's Guide (del6prog.hlp), топик "strings, declaring and initializing":
Declaring and initializing strings
...
Similarly, if you cast an empty string to a PChar, the result is a nil pointer. So, if you are passing such a PChar to a routine that needs to read or write to it, be sure that the routine can handle nil
...
У себя я такой темы не нашел, но если это так, то это ошибка справки
"Serginio1" <19608@news.rsdn.ru> сообщил/сообщила в новостях следующее: news:512759@news.rsdn.ru...
AP> Ну блин так ведь только что писалось, что pointer(s) хоть и должно быть nil, а все-таки не nil.
AP>S := ''; AP>Pointer(S) -> NIL AP>PChar(S) -> EmptyStr
AP>Первое нормально документировано, по второму не нашел информации в справке.
Лучше смотреть исходники
Исходники я смотрел, но они не являются документированой информацией и являются предметом для изменения. Поэтому их можно использовать только как вспомогательный вариант, и то только для конкретной версии. Например закрытие неудавшегося FindNext приводит к разными последствия в разных версиях. Поведение менялось и также отсутствовала информация о жизненноважных вещах. В справке по АПИ информация нормальная.
Документированое поведение гораздо важнее. Я просмотрел справку по Д3, Д5 и Д6 ситуация по строкам скажем мягко отвратительная.
Здравствуйте, Anatoly Podgoretsky, Вы писали:
AP> Лучше смотреть исходники AP>Исходники я смотрел, но они не являются документированой информацией и являются предметом для изменения. Поэтому их можно использовать только как вспомогательный вариант, и то только для конкретной версии. Например закрытие неудавшегося FindNext приводит к разными последствия в разных версиях. Поведение менялось и также отсутствовала информация о жизненноважных вещах. В справке по АПИ информация нормальная.
AP>Документированое поведение гораздо важнее. Я просмотрел справку по Д3, Д5 и Д6 ситуация по строкам скажем мягко отвратительная.
Из за моего плохого знания англицкого, мне легче разобраться с исходниками даже с применением окошка CPU. На самом деле в исходниках именно для данной версии все правильно. А сколько случаев когда в версиях многое меняется, и полной справки нет, не говоря об API и разных там Аппартаментах.
Лично для меня исходники большая информация чем справка и я могу ухватить всю суть нежели вникать в пространные повествования.
Лучше один раз увидеть (с комментариями желательно), чем сто раз услышать.
Но это лично мое мнение.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Leonid Troyanovsky, Вы писали:
LT> Ну, более интересно было б смотреть CharToOEM
Вот вся прелесть в Delphi в ее исходниках.
А CharToOEM извиняйте { Externals from user32.dll }
Хотя и свою сделать не долго взяв в руки таблицы кодировки.
и солнце б утром не вставало, когда бы не было меня
The stars so gaily glistened... (Tue, 20 Jan 2004 17:09:00 GMT @756)
...while the fading voice of Anatoly whispered through the darkness:
AP> Будет пытаться записать завершающий 0 AP> CharToOem(Pchar(S), Pchar(S));
Если я понял обсуждение — то это то же самое что CharToOem(nil,nil) ?
Я думал она вернет требуемый размер...
Разбаловался я с MultiByteToWideChar. (*)
Ну тогда давай так: CharToOemBuff(@s[1], @s[1], length(s))
Хотя там третий параметр описан странно:
DWORD cchDstLength // length of string to translate, in characters