Error identifier not found utf8tosys

Почему не определяется идентификатор UTF8ToConsole? Lazarus Решение и ответ на вопрос 2186193

alicesmagic

233 / 130 / 27

Регистрация: 24.08.2016

Сообщений: 874

1

07.02.2018, 17:13. Показов 12920. Ответов 23

Метки нет (Все метки)


Изучаю Лазарус по книге Мансурова «Основы программирования в среде Lazarus»

При компилировании такой программы:

Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
program summa;
{$mode objfpc}{$H+}
uses
    FileUtil; {Подключение модуля FileUtil для корректного
    отображиения русских букв с помощью функции UTF8ToConsole}
var
   result, A,B: integer;
begin
  readln(A, B);
  result:=A + B;
  writeln(UTF8ToConsole('1-е введенное число = '), A);
  writeln(UTF8ToConsole('2-е введенное число = '), B);
  writeln(UTF8ToConsole('Сумма двух чисел = '), result);
  readln
end.

выдается ошибка:
Компиляция проекта, цель: project1.exe: Код завершения 1, ошибок: 3
project1.lpr(11,11) Error: Identifier not found «UTF8ToConsole»
project1.lpr(12,11) Error: Identifier not found «UTF8ToConsole»
project1.lpr(13,11) Error: Identifier not found «UTF8ToConsole»

Зависимость LCL я подключила как написано в книжке. Программа написана тоже все как в книжке. Ошибок не нашла, сколько не искала. Помогите, пожалуйста понять, что не так.



0



volvo

Супер-модератор

Эксперт Pascal/DelphiАвтор FAQ

32451 / 20945 / 8105

Регистрация: 22.10.2011

Сообщений: 36,213

Записей в блоге: 7

07.02.2018, 18:04

2

Лучший ответ Сообщение было отмечено alicesmagic3d как решение

Решение

Pascal
1
2
uses
    LazUtf8;

должно быть (и добавить зависимость LazUtils)



2



233 / 130 / 27

Регистрация: 24.08.2016

Сообщений: 874

07.02.2018, 18:15

 [ТС]

3

Ошибку не выдает в таком случае, но русский текст отображается некорректно:

Название: 30fb5e9bacc41722acd19ad627993a11.jpg
Просмотров: 274

Размер: 6.2 Кб



0



Супер-модератор

Эксперт Pascal/DelphiАвтор FAQ

32451 / 20945 / 8105

Регистрация: 22.10.2011

Сообщений: 36,213

Записей в блоге: 7

07.02.2018, 18:27

4

Ну, это проблемы Windows, наверняка, ибо:

Миниатюры

Почему не определяется идентификатор UTF8ToConsole?
 



1



Супер-модератор

Эксперт Pascal/DelphiАвтор FAQ

32451 / 20945 / 8105

Регистрация: 22.10.2011

Сообщений: 36,213

Записей в блоге: 7

07.02.2018, 18:50

5

Хотя и под Windows все нормально:

Миниатюры

Почему не определяется идентификатор UTF8ToConsole?
 



1



233 / 130 / 27

Регистрация: 24.08.2016

Сообщений: 874

07.02.2018, 19:22

 [ТС]

6

Да. Странное дело.
Однако, проблема решилась следующим образом.
В окне кода ПКМ — Параметры файла — Кодировка — CP866
А в коде вообще убрала функцию UTF8ToConsole.
Можно даже не подключать LazUtf8 и не добавлять зависимость от LCL. Сплошные плюсы



0



alicesmagic

233 / 130 / 27

Регистрация: 24.08.2016

Сообщений: 874

08.02.2018, 21:30

 [ТС]

7

Все равно путаница получается при таких настройках.
Кириллица отображается корректно в одном случае, и некорректно в другом.

Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
program function_length;
{$mode objfpc}{$H+}
uses
    CRT, FileUtil, SysUtils, LazUtf8;
var
  S,S1:string;
  i:integer;
begin
  S:='Ivanov';
  i:=Length(S);
  writeln(S,' ',i);
  S1:='Иванов';
  i:=Length(S1);
  writeln(S1,' ',i);
  writeln('Для выхода из программы нажмите любую клавишу');
  readkey
end.

Попробуйте кто-нибудь еще на Windows, пожалуйста. Что получится?

Миниатюры

Почему не определяется идентификатор UTF8ToConsole?
 



0



233 / 130 / 27

Регистрация: 24.08.2016

Сообщений: 874

08.02.2018, 21:43

 [ТС]

8

P.S. Выяснила, что в данном случае причиной ошибки являются модули FileUtil и LazUtf8. Если их отключить, то программа работает корректно.
Я их не отключала из принципа «кашу маслом не испортишь»… оказалось что «испортишь»)))



0



Джоуи

1073 / 635 / 240

Регистрация: 05.05.2015

Сообщений: 3,546

Записей в блоге: 2

08.02.2018, 22:35

9

Лучший ответ Сообщение было отмечено alicesmagic3d как решение

Решение

alicesmagic3d, за Вас с этой проблемой сталкивались тысячи других программистов/студентов/школьников, не надо «ломать систему», потом будет поздно, когда начнете писать сложную программу и будут возникать «неакадемические» проблемы, не нужно всяких

Цитата
Сообщение от alicesmagic3d
Посмотреть сообщение

модули FileUtil и LazUtf8. Если их отключить, то программа работает корректно.

и

Цитата
Сообщение от alicesmagic3d
Посмотреть сообщение

Однако, проблема решилась следующим образом.
В окне кода ПКМ — Параметры файла — Кодировка — CP866

Это во-первых.
Во-вторых, какая у Вас версия Лазарус? Если 1.6 и позже, Вы должны были заметить предупреждение UTF8ToConsole is deprecated: «Use the function in LazUTF8 unit», то есть UTF8ToConsole устарела, используйте версию из модуля LazUTF8, именно то, что Вам подсказал volvo

И третье

Цитата
Сообщение от alicesmagic3d
Посмотреть сообщение

Попробуйте кто-нибудь еще на Windows, пожалуйста. Что получится?

Я создал новый проект, скопировал Ваш код из первого поста как есть, подключил LCL, в uses прописал LazUTF8: вуаля (у меня Lazarus 1.6)

Миниатюры

Почему не определяется идентификатор UTF8ToConsole?
 



1



Джоуи

1073 / 635 / 240

Регистрация: 05.05.2015

Сообщений: 3,546

Записей в блоге: 2

08.02.2018, 22:36

10

Создайте проект с нуля и перепробуйте



1



alicesmagic

233 / 130 / 27

Регистрация: 24.08.2016

Сообщений: 874

09.02.2018, 02:11

 [ТС]

11

Я, собственно, и просила, чтобы мне подсказали, что делать дальше, после того как замена FileUtil на LazUtf8 не решила проблему. Volvo спасибо за подсказку, но дальше не было указаний, вот я и начала экспериментировать. Создать новый проект с нуля не догадалась, хотя это и оказалось самым верным решением. Сейчас все работает. Большое спасибо за науку!

Добавлено через 1 минуту
Я уже всем надоела, но у меня опять проблемка и опять с килиллицей.
Только теперь не в консольной программе, а в приложении.
Текст должен считываться из текстового файла и прописываться в Memo по такому коду:

Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
procedure TForm1.ButtonShowClick(Sender: TObject);
var
  Ch:Char;  {описание переменной, в которую будет считывать символ из файла}
begin
  Memo1.Lines.Text:='';      // очистка окна Memo1
  {$I-}
    Reset(db);               // открыть файл для чтения
  {$I+}
  if IOResult = 0 then
  begin
    while not Eof(db) do              // пока не конец файла
      begin
        Read(db,Ch);                  // прочитать из файла символ
        Memo1.Text:=Memo1.Text+Ch;    // вывести символ в поле Memo1
      end;
   CloseFile(db);                     // закрыть файл
   end;
end;

Но, почему-то, выводятся только латинские символы. Русские не попадают в мемо. Если в файле написано «wwwяяяqqq», то в мемо выводится так «wwwqqq».
В чем может быть проблема? Подскажите, пожалуйста!



0



Супер-модератор

Эксперт Pascal/DelphiАвтор FAQ

32451 / 20945 / 8105

Регистрация: 22.10.2011

Сообщений: 36,213

Записей в блоге: 7

09.02.2018, 04:18

12

Лучший ответ Сообщение было отмечено ZX Spectrum-128 как решение

Решение

alicesmagic3d, это зависит от того, в какой кодировке записан файл. Если 1251 — то Загрузка в Memo текста из файла в кодировке Win (cp1251), для других — соответственно поменять функцию…



0



alicesmagic

233 / 130 / 27

Регистрация: 24.08.2016

Сообщений: 874

09.02.2018, 14:08

 [ТС]

13

Pascal
1
2
3
4
5
6
7
8
implementation
 
{$R *.lfm}
 
const
  DBNAME='111.txt'; // имя текстового файла
var
  db:TextFile;         // файл - база данных

Файл 111.txt создается с помощью «Rewrite(db)» в кодировке utf-8 (я проверила уже созданный файл). Файл unit1.pas тоже в utf-8 по умолчанию (на всякий случай я тоже проверила). Форматы обоих файлов совпадают.

Добавлено через 25 минут
И даже создание проекта с нуля не помогло. Та же самая ошибка.



0



Джоуи

1073 / 635 / 240

Регистрация: 05.05.2015

Сообщений: 3,546

Записей в блоге: 2

10.02.2018, 10:11

14

alicesmagic3d, для начала поменяйте способ работы с файлами (через потоки)
Сохранение и чтение из файла (абзацы чтение и сохранение через потоки)



1



233 / 130 / 27

Регистрация: 24.08.2016

Сообщений: 874

11.02.2018, 17:54

 [ТС]

15

Это уже слишком сложно для меня. Отложу пока эту проблему. Однако, большое спасибо всем за помощь!

Последний вопросик по этой же теме.

Функция «UTF8Length» НЕ определяется. Модуль «LCLProc» подключен. Версия Лазаруса — последняя.
Так и должно быть? Или я опять где-то торможу?
Как определить «правильную» длину строки в которой могут присутствовать русские буквы?



0



Джоуи

1073 / 635 / 240

Регистрация: 05.05.2015

Сообщений: 3,546

Записей в блоге: 2

11.02.2018, 18:29

16

Цитата
Сообщение от alicesmagic3d
Посмотреть сообщение

UTF8Length

подключите в uses LazUTF8



1



233 / 130 / 27

Регистрация: 24.08.2016

Сообщений: 874

11.02.2018, 19:18

 [ТС]

17

Блин. Точно торможу! Вернулись к тому, с чего начали. Спасибо большое! Тема исчерпана)



0



0 / 0 / 0

Регистрация: 10.04.2018

Сообщений: 8

10.04.2018, 08:23

18

Цитата
Сообщение от Joey
Посмотреть сообщение

Вы должны были заметить предупреждение UTF8ToConsole is deprecated: «Use the function in LazUTF8 unit»

А где это предупреждение можно было заметить? Я ничего такого не увидел, хотя и очень пытался (Lazarus 1.8).
У меня возникла та же проблема. Добавление модуля LazUTF8 исправило ситуацию.
Но хотелось бы понять принцип решения проблем (не заводить же каждый раз тему на форуме).



0



588 / 539 / 206

Регистрация: 24.01.2012

Сообщений: 1,331

10.04.2018, 12:02

19

Цитата
Сообщение от has70
Посмотреть сообщение

А где это предупреждение можно было заметить?

Вот здесь

Миниатюры

Почему не определяется идентификатор UTF8ToConsole?
 



0



0 / 0 / 0

Регистрация: 10.04.2018

Сообщений: 8

13.04.2018, 06:52

20

Цитата
Сообщение от edukra
Посмотреть сообщение

Вот здесь

Цитата
Сообщение от edukra
Посмотреть сообщение

Цитата
Сообщение от has70

А где это предупреждение можно было заметить?

Вот здесь…

У меня такого сообщения нет. У меня просто «Identifier not found»

Миниатюры

Почему не определяется идентификатор UTF8ToConsole?
 



0



Topic: compile path/missing unit problems  (Read 7173 times)

fpc 2.5.1
Lazarus 0.9.29
Ubuntu 9.10

When I try to compile my app I get missing-unit errors.  I fixed the first one by manually locating FileUtil and adding it to my compile path. 

Now, I get «Can’t find unit WEReferences used by LCLProc.»  I’m assuming this could go on ad infinitum.

Is there a problem with my fpc/Lazarus install?  I did it by installing CodeTyphon?  Is that a mistake?

Is there an easy way to set up all the compiler paths?

Thanks.


Logged


fpc 2.5.1
Lazarus 0.9.29
Ubuntu 9.10

When I try to compile my app I get missing-unit errors.  I fixed the first one by manually locating FileUtil and adding it to my compile path. 

You should never add the LCL sources to your compile path. Only point to the dir where the compiled units of the LCL are. Normally the IDE will do this for you if you add a depencency to the LCL to your project.

Now, I get «Can’t find unit WEReferences used by LCLProc.»  I’m assuming this could go on ad infinitum.

Yes, that was to be expected.

Is there a problem with my fpc/Lazarus install?  I did it by installing CodeTyphon?  Is that a mistake?

Is there an easy way to set up all the compiler paths?

I don’t know codetyphoon, but I thought it set this up for you. For a normal project, you don’t have to specify any special dir.
The only thing you have to configure the first time in the environment options are the path to the compiler, the lazarus sources and the fpc sources. IIRC codetyphoon does that for you.


Logged

//—
{$I stdsig.inc}
//-I still can’t read someones mind
//-Bugs reported here will be forgotten. Use the bug tracker


You should never add the LCL sources to your compile path. Only point to the dir where the compiled units of the LCL are. Normally the IDE will do this for you if you add a depencency to the LCL to your project.

By dependency you mean putting a unit in the uses clause or just calling a function that is in a library unit?

Yes, that was to be expected.

Why, and what do I do about it?

I don’t know codetyphoon, but I thought it set this up for you. For a normal project, you don’t have to specify any special dir.
The only thing you have to configure the first time in the environment options are the path to the compiler, the lazarus sources and the fpc sources. IIRC codetyphoon does that for you.

I’ve added 2 screen shots, one for my Project Compiler Options and the other for Environment | Files.  Do you see anything wrong with the way this was set up at install?

Thanks!

« Last Edit: December 17, 2009, 04:45:26 am by mbohn »


Logged


I meant, adding it to the «other unit files» option of your project options. From your screenshot I see you didn’t, so that’s good.

You mentioned that you added something to your file path, where did you do that ?


Logged

//—
{$I stdsig.inc}
//-I still can’t read someones mind
//-Bugs reported here will be forgotten. Use the bug tracker


I removed those after reading your first response, but I can reconstruct for you what I did:

First time I tried to compile my app I get the following compile error:

«Identifier not found UTF8ToSys» which is in the FileUtil unit.
I search for that unit and find the .pas file in /usr/lib/lazarus/lcl.
I add that path to Project Compiler Options, I think in the «Other Unit Files» section.

But more to the point, are the screen shots correct as you see them above?

If so, how do I fix the «Identifier not found UTF8ToSys» problem?  And will that fix other missing unit errors?

Thanks.


Logged


Your screenshots are ok. Don’t change it.

Did you add FileUtil to the uses clause of the unit where you want to use UTF8ToSys ?


Logged

//—
{$I stdsig.inc}
//-I still can’t read someones mind
//-Bugs reported here will be forgotten. Use the bug tracker


Yes, and that has now gotten me past that problem.  Hopefully, the others will go away too.

Thanks much for your help.


Logged


Александр Яшин писал(а):Так компилируется, но в Symbol нечитаемый символ!

Без примера тут будет проблематично разобраться. «Читаемый» и «нечитаемый» — понятия относительные, зависят от того как выводить, куда выводить и под какой ОС всё это происходит. Если выводить на форму — то для читабельности нужно его преобразовывать обратно в UTF-8 вне зависимости от платформы, в консоль под Linux — тоже чаще всего в UTF-8, в в консоль под Windows — в кодировку OEM Cyrillic (866).

Александр Яшин писал(а):Похоже тип char в Unicode поддерживается только для кодов < 128

Тип char и Unicode — это две разные вещи. Char — это кусочек памяти размером ровно в один байт. Юникод — это способ кодирования символов, его конкретная разновидность, UTF-8, требует от одного до четырёх байт памяти на один символ. По одному байту — на символы латиницы, для совместимости, на кириллицу — по два, на восточные кодировки — 3 и 4 байта. Разумеется, что любой символ UTF-8 не влезет в один байт переменной типа char. Это всё равно что переливать воду из четырёхлитрового бочонка в литровую банку. Если в бочонке было меньше литра (читай «< 128») — наше счастье, но полагаться на это никоим образом нельзя.

И кстати, можете заглянуть в исходники и посмотреть, что такое TUTF8Char :) Ctrl+щелчок мышкой на типе переменной.

Код: Выделить всё
TUTF8Char = String[7];

    msm.ru

    Нравится ресурс?

    Помоги проекту!

    В этом разделе можно создавать темы, которые относятся к поколению 32-битных компиляторов.
    Здесь решаются вопросы портирования кода из старого доброго Турбо Паскаля в FPC, TMT, VP, GPC компиляторы, а также особенностей программирования на них для Windows/Linux и других ОС.
    Указывайте тип компилятора, его версию, а также платформу (Windows/Linux/..) компиляции, другими словами, Target.


    • Библиотека MSDN MSDN Library Online | RSDN — RUSSIAN SOFTWARE DEVELOPER NETWORK
    • Free Pascal manuals [по-русски] | TMT Pascal Reference | VP Manuals

    >
    Кириллические имена файлов и Lazarus
    , Сбой при попытке работы с файлом

    • Подписаться на тему
    • Сообщить другу
    • Скачать/распечатать тему



    Сообщ.
    #1

    ,
    06.09.10, 22:29

      Moderator

      *******

      Рейтинг (т): 878

      Привет всем.

      Итак, частично проблема описана в названии. А теперь — немного конкретики. Имеется: WinXP SP3 (неюникодный язык выставлен не в Cyrillic, а в Hebrew — это важно) и Lazarus 0.9.28.2

      При попытке выполнить

      ExpandedWrap disabled

          if SaveDialog1.Execute then

          begin

            ShowMessage(SaveDialog1.FileName);

            memo.SaveToFile(SaveDialog1.FileName);

          end;

      , где SaveDialog1.FileName содержит символы кириллицы, например, ‘F:тест.txt’, происходит сбой (см. аттач, нижняя часть картинки), хотя ShowMessage отображает правильный путь (см. аттач, верхняя часть). Да, я читал обсуждение на freepascal.ru, естественно, я пробовал и UTF8Decode и UTF8ToSys, но ни одно ни другое не приводит к работе SaveToFile, поскольку у меня системная кодировка другая, в ней не отображаются кириллические символы. Файл с именем на английском (или иврите) прекрасно сохраняется безо всяких преобразований, вышеприведенным фрагментом кода.

      При этом, вот такой вызов WinAPI-шной функции:

      ExpandedWrap disabled

        if not CopyFileW(PWideChar(UTF8Decode(SrcName)),PWideChar(UTF8Decode(DstName)), False) then

        begin

          //

        end;

      копирует файлы с любыми именами, хоть русскими, хоть ивритскими, хоть арабскими.

      Внимание, вопрос: можно ли каким-либо образом заставить Лазарус понять, что имена файлов могут быть не на двух, а на гораздо бОльшем количестве языков (желательно не используя WinAPI)? Обходной путь — сохранить в файл с латинским именем, а потом переименовать его, как нужно — мне известен, хотелось бы без лишних телодвижений…


      Прикреплённый файлПрикреплённый файлtest.PNG (15,05 Кбайт, скачиваний: 994)


      daesher



      Сообщ.
      #2

      ,
      10.09.10, 07:35

        Очень похоже на то, что Win32-интерфейс Lazarus (по крайней мере, версии 0.9.28-2) использует ANSI-вариант функций WinAPI для работы с файлами. Надо смотреть текущую SVN-версию, исправлять её (если баг ещё есть), отсылать патч разработчикам (последнее как раз несложно). Либо создавать обходные варианты с принудительным преобразованием кода из UTF8 в CP1251.

        Сообщение отредактировано: daesher — 10.09.10, 07:36

        Guru

        Romtek



        Сообщ.
        #3

        ,
        13.09.10, 12:25

          пропагандист

          *******

          Рейтинг (т): 188

          По-моему, проблема сидит глубоко в RTL и связана с преобразованиями имён или даже типами вызова Ansi/Wide character. Я бы сказал, что это проблема чисто системной связки RTL FPC.

          Добавлено 13.09.10, 12:33

          Цитата daesher @ 10.09.10, 07:35

          Либо создавать обходные варианты с принудительным преобразованием кода из UTF8 в CP1251.

          Только UTF-8 в Windows не используется, если я не ошибаюсь. Используется UTF-16 (с двойным байтом на символ).

          Как только полностью перейдут на Wide character функции (Unicode), подобные проблемы отпадут.

          0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)

          0 пользователей:

          • Предыдущая тема
          • 32-битные компиляторы
          • Следующая тема

          Рейтинг@Mail.ru

          [ Script execution time: 0,0300 ]   [ 18 queries used ]   [ Generated: 9.02.23, 13:56 GMT ]  

          Since the default character set of Lazarus from version 1.2 is UTF8, if you want to switch to the normal display of the system or save text, the character set must be converted. Lazarus provides many functions. As the title.

          So what does it matter?

          UTF8ToSys needs to enable the compilation parameter -dDisableUTF8RTL, otherwise it is still UTF8, if it is modified, it is still Utf8ToAnsi, but basic processing is done.

          image

          Corresponding code

          function UTF8ToSys(const s: string): string;
          begin
            {$IFDEF UTF8_RTL}
            Result:=s;
            {$ELSE}
            if NeedRTLAnsi and (not IsASCII(s)) then
              Result:=UTF8ToAnsi(s)
            else
              Result:=s;
            {$ENDIF}
          end;

          Utf8ToAnsi comes with freePascal, transcoded to Ansi, in the ustringh.inc file

          function Utf8ToAnsi(const s : RawByteString) : RawByteString;{$ifdef SYSTEMINLINE}inline;{$endif}
            begin
              Result:=RawByteString(Utf8Decode(s));
            end;
          {$ifdef FPC_HAS_CPSTRING}
            RawByteString       = type AnsiString(CP_NONE);
          {$else FPC_HAS_CPSTRING}
            RawByteString       = ansistring;
          {$endif FPC_HAS_CPSTRING}

          UTF8ToWinCP is a Lazarus package for Windows. It does not change the code page, only the character encoding.

          {$ifdef WinCe}
          function UTF8ToWinCP(const s: string): string; inline;
          begin
            Result := Utf8ToSys(s);
          end;
          {$else}
          function UTF8ToWinCP(const s: string): string;
          // result has codepage CP_ACP
          var
            src: UnicodeString;
            len: LongInt;
          begin
            Result:=s;
            if IsASCII(Result) then begin
              {$ifdef FPC_HAS_CPSTRING}
              // prevent codepage conversion magic
              SetCodePage(RawByteString(Result), CP_ACP, False);
              {$endif}
              exit;
            end;
            src:=UTF8Decode(s);
            if src='' then
              exit;
            len:=WideCharToMultiByte(CP_ACP,0,PUnicodeChar(src),length(src),nil,0,nil,nil);
            SetLength(Result,len);
            if len>0 then begin
              WideCharToMultiByte(CP_ACP,0,PUnicodeChar(src),length(src),@Result[1],length(Result),nil,nil);
              {$ifdef FPC_HAS_CPSTRING}
              // prevent codepage conversion magic
              SetCodePage(RawByteString(Result), CP_ACP, False);
              {$endif}
            end;
          end;
          {$endif not wince}

          UTF8ToConsole is a Lazarus package for Windows. After the code is changed, it will also be configured as the default code page text.

          {$ifdef WinCe}
          function UTF8ToConsole(const s: string): string; // converts UTF8 to console string (used by Write, WriteLn)
          begin
            Result := UTF8ToSys(s);
          end;
          {$else}
          function UTF8ToConsole(const s: string): string; // converts UTF8 to console string (used by Write, WriteLn)
          var
            Dst: PChar;
          begin
            {$ifndef NO_CP_RTL}
            Result := UTF8ToWinCP(s);
            {$else NO_CP_RTL}
            Result := UTF8ToSys(s); // Kept for compatibility
            {$endif NO_CP_RTL}
            Dst := AllocMem((Length(Result) + 1) * SizeOf(Char));
            if CharToOEM(PChar(Result), Dst) then
              Result := StrPas(Dst);
            FreeMem(Dst);
            {$ifndef NO_CP_RTL}
            SetCodePage(RawByteString(Result), CP_OEMCP, False);
            {$endif NO_CP_RTL}
          end;
          {$endif not WinCE}

          I have a program here where I invert the case of an entered string. This is the code in my .cpp file and I am using Visual Studio C++ IDE. I am not sure what I need in a header file or if I need one to make this work.

          Error with my function call swapCase. Main does not see swapCase for some reason that I’m not sure of.

          #include <cctype>
          #include <iostream>
          #include <conio.h>
          
          using namespace std;
          
          int main()
          {
              char name[30];
              cout<<"Enter a name: ";
              cin.getline(name, 30);
              swapCase(name);
              cout<<"Changed case is: "<< name <<endl;
              _getch();
              return 0;
          }
          
          void swapCase (char* name)
          {
              for(int i=0;name[i];i++)
              {
                  if ( name[i] >= 'A' && name[i] <= 'Z' )
                      name[i] += 32; //changing upper to lower
                  else if( name[i] >= 'a' && name[i] <= 'z')
                      name[i] -= 32; //changing lower to upper
              }
          }
          

          Any other tips for syntax or semantics is appreciated.

          Bart's user avatar

          Bart

          19.3k7 gold badges70 silver badges77 bronze badges

          asked Nov 30, 2011 at 16:11

          KRB's user avatar

          1

          Add this line before main function:

          void swapCase (char* name);
          
          int main()
          {
             ...
             swapCase(name);    // swapCase prototype should be known at this point
             ...
          }
          

          This is called forward declaration: compiler needs to know function prototype when function call is compiled.

          hichris123's user avatar

          hichris123

          10k15 gold badges55 silver badges69 bronze badges

          answered Nov 30, 2011 at 16:13

          Alex F's user avatar

          Alex FAlex F

          41.8k41 gold badges142 silver badges210 bronze badges

          3

          Unlike other languages you may be used to, everything in C++ has to be declared before it can be used. The compiler will read your source file from top to bottom, so when it gets to the call to swapCase, it doesn’t know what it is so you get an error. You can declare your function ahead of main with a line like this:

          void swapCase(char *name);
          

          or you can simply move the entirety of that function ahead of main in the file. Don’t worry about having the seemingly most important function (main) at the bottom of the file. It is very common in C or C++ to do that.

          answered Nov 30, 2011 at 16:19

          Michael Kristofik's user avatar

          Michael KristofikMichael Kristofik

          33.9k15 gold badges78 silver badges124 bronze badges

          At the time the compiler encounters the call to swapCase in main(), it does not know about the function swapCase, so it reports an error. You can either move the definition of swapCase above main, or declare swap case above main:

          void swapCase(char* name);
          

          Also, the 32 in swapCase causes the reader to pause and wonder. The comment helps! In this context, it would add clarity to write

          if ('A' <= name[i] && name[i] <= 'Z')
              name[i] += 'a' - 'A';
          else if ('a' <= name[i] && name[i] <= 'z')
              name[i] += 'A' - 'a';
          

          The construction in my if-tests is a matter of personal style. Yours were just fine. The main thing is the way to modify name[i] — using the difference in ‘a’ vs. ‘A’ makes it more obvious what is going on, and nobody has to wonder if the ’32’ is actually correct.

          Good luck learning!

          answered Nov 30, 2011 at 16:20

          Kevin Hopps's user avatar

          Kevin HoppsKevin Hopps

          6973 silver badges8 bronze badges

          You have to define void swapCase before the main definition.

          answered Nov 30, 2011 at 16:13

          v01d's user avatar

          v01dv01d

          1,4471 gold badge11 silver badges22 bronze badges








          English (en)








          日本語 (ja)






          русский (ru)









          Введение

          Здесь описывается поддержка Unicode в «программах» Lazarus (консольных или серверных, без графического интерфейса) и «приложениях» (GUI с использованием LCL) при использовании особенностей FPC 3.0+.

          Решение является кросс-платформенным и использует кодировку UTF-8, которая отличается от UTF-16 Delphi, но вы можете написать код, полностью совместимый с Delphi на уровне исходного кода, запомнив лишь несколько правил.

          Поддержка Unicode включается автоматически для приложений LCL начиная с Lazarus 1.6.0 при компиляции с FPC 3.0+.

          Старый метод поддержки UTF-8 в LCL при использовании FPC версий до 2.6.4 включительно, описан здесь: LCL Unicode Support

          RTL с кодовой страницей UTF-8 по умолчанию

          По умолчанию RTL использует системную кодовую страницу для AnsiStrings (в таких операциях, как например FileExists и TStringList.LoadFromFile). Под Windows это не-Unicode кодировка, поэтому могут использоваться только символы из текущей языковой группы (не более 256 символов).
          LCL, с другой стороны, работает с кодировкой UTF-8, охватывающей весь диапазон Unicode. Под Linux и macOS UTF-8 обычно является системной кодовой страницей, и здесь RTL использует по умолчанию CP_UTF8.

          FPC, начиная с версии 3.0, обеспечивает API для изменения кодовой страницы RTL по умолчанию на другое значение. Lazarus (конкретно пакет LazUtils) использует данный API и изменяет кодовую страницу RTL по умолчанию на UTF-8 (CP_UTF8). Это означает, что пользователи Windows также могут теперь использовать строки UTF-8 в RTL.

          • Например, FileExists и StringList.LoadFromFile(Filename) теперь имеют полную поддержку Unicode. См. Полный перечень функций, которые полносттью поддерживают Unicode, здесь:

          RTL changes

          • AnsiToUTF8, UTF8ToAnsi, SysToUTF8, UTF8ToSys не работают (не изменяют передаваемых данных). Эти функции обычно использовались для упомянутых выше функций RTL, которые больше не нуждаются в преобразованиях. Относящееся к функциям WinAPI, см ниже.
          • Многочисленные вызовы UTF8Encode и UTF8Decode больше не требуются, потому что такие действия при присваивании значений UnicodeString переменным типа String и наоборот компилятор делает автоматически.
          • При работе с WinAPI необходимо использовать «W»-функции или пользоваться функциями UTF8ToWinCP и WinCPToUTF8. То же верно для библиотек, которые до сих пор используют Ansi WinAPI функции. Например, в FPC 3.0 и более ранних версиях в этом нуждается unit registry.
          • «String» и «UTF8String» — различные типы. Если вы присваиваете значение String переменной типа UTF8String, компилятор добавляет код для проверки совпадения кодировок. Это будет стоить дополнительного времени исполнения и увеличит размер кода. Просто используйте String вместо UTF8String.
          • Консоль Windows использует кодировку, которая может отличаться от системной (в случае русского языка это всегда именно так). writeln в FPC 3.0+ автоматически преобразует строки UTF-8 в кодовую страницу консоли. Некоторые консольные программы Windows ожидают на входе строки в кодировке консоли и результаты своей работы также выдают в кодовой странице консоли. Для соответствующего преобразования можно использовать функции UTF8ToConsole и ConsoleToUTF8.

          Дополнительная информация о новинках поддержки Unicode в FPC:
          FPC Unicode support

          Использование

          Следуйте простым правилам:

          • Используйте как обычно тип «String» вместо UTF8String или UnicodeString.
          • Всегда присваивайте константу переменной типа String.
          • Используйте тип UnicodeString явно для вызовов API, когда это необходимо.

          Эти правила делают большую часть кода уже совместимым с Delphi при использовании настроек проекта по умолчанию.

          Применение в Lazarus

          Новый режим включается автоматически при компиляции FPC 3.0+.
          Это поведение может быть отключено директивой компиляции -dDisableUTF8RTL, детали см. на странице Lazarus with FPC3.0 without UTF-8 mode.

          Если вы используете строковые литералы в новом режиме, ваши исходники всегда должны быть в кодировке UTF-8.
          Однако, ключ -FcUTF8 на самом деле обычно не требуется. Дополнительные сведения приведены ниже, в разделе «Строковые литералы».

          Что же на самом деле происходит в новом режиме? В секции предварительной инициализации вызываются две FPC функции, устанавливающие кодировку строк по умолчанию в исполняющих библиотеках FPC в UTF-8 :

           SetMultiByteConversionCodePage(CP_UTF8);
           SetMultiByteRTLFileSystemCodePage(CP_UTF8);
          

          Кроме того, функции UTF8…() из LazUTF8 (LazUtils) устанавливаются в качестве функций обратного вызова для функций RTL, имена которых начинаются с Ansi…().

          Использование UTF-8 в программах без LCL

          В не LCL-проекте добавьте зависимость для пакета LazUtils. Затем добавьте модуль LazUTF8 в секцию uses основного файла программы. Он должен быть в начале, сразу после критических менеджеров памяти и многопоточности (например, cmem, heaptrc, cthreads).

          Вызов функций API, которые используют WideString или UnicodeString

          Если тип параметра WideString или UnicodeString, вы можете просто передать ему строку. Компилятор преобразует данные автоматически. Появится предупреждение о преобразовании из AnsiString в UnicodeString, которое можно либо проигнорировать, либо подавить, приведя тип String к UnicodeString.

          Переменная S в приведенных ниже примерах определяется как String, что здесь означает AnsiString.

          procedure ApiCall(aParam: UnicodeString);  // Определение
           ...
          ApiCall(S);                // вызов со строкой S, игнорируя предупреждение.
          ApiCall(UnicodeString(S)); // вызов со строкой S, подавляя предупреждение (приведение String к UnicodeString).
          

          Когда тип параметра является указателем PWideChar, вам нужна временная переменная UnicodeString. Присвойте ей свою строку. Затем компилятор преобразует эти данные. Затем введите временную переменную в PWideChar.

          procedure ApiCallP(aParamP: PWideChar);  // Определение
           ...
          var Tmp: UnicodeString;   // Временная переменная
           ...
          Tmp := S;                 // Присваиваем String -> UnicodeString.
          ApiCallP(PWideChar(Tmp)); // Вызов переменной temp, приведение к указателю
          

          Note-icon.png

          Примечание: в обоих случаях код совместим с Delphi. Это означает, что вы можете скопировать/вставить его в Delphi, и он сработает на 100% правильно. В Delphi String проецируется в UnicodeString.

          Типичным случаем является вызов Windows API. Только должны вызываться их версии «W», потому что они поддерживают Unicode.
          Обычно используйте UnicodeString также с Windows API. WideString необходим только при программировании COM/OLE, где ОС заботится об управлении памятью.

          Чтение / запись текстового файла с кодовой страницей Windows

          Это не совместимо ни с Delphi, ни с прежним кодом Lazarus. На практике вы должны инкапсулировать код, связанный с системной кодовой страницей, и преобразовать данные в UTF-8 как можно быстрее.

          Либо используйте RawByteString и сделайте явное преобразование…

          uses ... , LConvEncoding;
           ...
          var
            StrIn: RawByteString;
            StrOut: String;
           ...
          StrOut := CP1252ToUTF8(StrIn,true);  // Использует фиксированную кодовую страницу
          // или
          StrOut := WinCPToUTF8(StrIn,true);  // Использует системную кодовую страницу на этом конкретном компьютере
          

          … или установите правильную кодовую страницу для существующей строки

          var
            StrIn: String;
           ...
          SetCodePage(RawByteString(StrIn), 1252, false);  // Фиксированная 1252 (или Windows.GetACP())
          

          Note-icon.png

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

          Windows.GetACP() возвращает системную кодовую страницу Windows.

          Код, который очень сильно зависит от кодовой страницы Windows

          Существует «план B» для кода, который очень сильно зависит от системной кодовой страницы Windows или должен записываться в консоль Windows за пределами кодовой страницы консоли.
          См.: Lazarus с FPC3.0 без режима UTF-8.
          К счастью, это нужно нечасто. В большинстве случаев проще конвертировать данные в UTF-8.

          Запись в консоль

          Вывод консоли Windows работает корректно, если ваши символы принадлежат кодовой странице консоли.
          Например, символ для рисования рамки ‘╩’ в кодовой странице CP437 составляет один байт #202 и часто используется так:

          Когда вы конвертируете код в UTF-8, например, используя пункт всплывающего меню редактора исходного кода Lazarus File Settings (Параметры файла) / Encoding (Кодировка) / UTF-8, и нажимая кнопку диалога «Change file on disk» (Изменить файл на диске), символ ‘╩’ становится 3-х байтным (#226#149#169), поэтому литерал становится строкой.

          Процедуры write и writeln преобразуют строку UTF-8 в текущую кодовую страницу консоли. Таким образом, ваша консольная программа теперь выводит ‘╩’ в Windows с любой кодовой страницей (т.е. не только с CP437), и она даже работает в Linux и macOS. Вы также можете использовать ‘╩’ в строках LCL, например, Memo1.Lines.Add(‘╩’);

          Если ваши символы не принадлежат кодовой странице консоли, все усложняется. Тогда вы вообще не сможете использовать новую систему Unicode.
          См.:
          Проблема Системной кодировки и Консольной кодировки (Windows)

          Символы Юникода и кодовые точки в коде

          См. детали для UTF-8 в UTF8 strings and characters.

          Функции кодовых точек для кодирования независимого кода

          В пакете LazUtils есть модуль LazUnicode со специальными функциями для работы с кодовыми точками, независимо от кодировки.
          Они используют функции UTF8…() из LazUTF8 при использовании в режиме UTF-8, и функции UTF16…() из LazUTF16 при использовании в {$ModeSwitch UnicodeStrings} FPC или в Delphi (да, Delphi поддерживается!).

          В настоящее время {$ModeSwitch UnicodeStrings} можно протестировать, задав «UseUTF16».
          Также есть тестовая программа LazUnicodeTest в каталоге components/lazutils/test. Она имеет 2 режима сборки, UTF8 и UTF16, для удобства тестирования. Тестовая программа также поддерживает Delphi, тогда, очевидно, используется режим UTF-16.

          LazUnicode позволяет одному исходному коду работать между:

          • Lazarus с его UTF-8 решением.
          • Будущие FPC и Lazarus с Delphi-совместимым решением UTF-16.
          • Delphi, где String = UnicodeString.

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

          • CodePointCopy() — аналогична UTF8Copy()
          • CodePointLength() — аналогична UTF8Length()
          • CodePointPos() — аналогична UTF8Pos()
          • CodePointSize() — аналогична UTF8CharacterLength() (функция устарела. Вместо нее используйте UTF8CodepointSize. См. подробнее)
          • UnicodeToWinCP() — аналогична UTF8ToWinCP()
          • WinCPToUnicode() — аналогична WinCPToUTF8()

          Этот режим также предоставляет перечислитель для кодовых точек, который компилятор использует для цикла for-in.
          В результате, независимо от кодировки, этот код работает:

           var s, ch: String;
           ...
           for ch in s do
             writeln('ch=',ch);
          

          Delphi не предоставляет аналогичные функции для CodePoints в своем решении UTF-16.
          Практически большая часть кода Delphi рассматривает UTF-16 как кодировку с фиксированной шириной, что привело к возникновению большого количества неработающего кода UTF-16.
          Это означает, что использование LazUnicode также для Delphi улучшит качество кода!

          Для использования Delphi необходимы оба модуля LazUnicode и LazUTF16.

          Строковые литералы

          Исходный код должен сохраняться в кодировке UTF-8. Lazarus создает такие файлы по умолчанию.
          Вы можете изменять кодировку импортированных файлов, щелкая правой кнопкой мыши в редакторе исходного кода / File Settings (Настройки файла) / Encoding (Кодировка).

          Обычно директива {$codepage utf8} / -FcUTF8 не требуется. Это довольно нелогично, поскольку значение этого флага заключается в обработке строковых литералов как UTF-8. Однако новый режим UTF-8 переключает кодирование во время выполнения, а константы оцениваются во время компиляции.

          Таким образом, без -FcUTF8 компилятор (ошибочно) считает, что строковая константа кодируется системной кодовой страницей. Затем он видит переменную String с кодировкой по умолчанию (которая будет изменена на UTF-8 во время выполнения, но компилятор этого не знает). Таким образом, то же для кодировки по умолчанию, преобразование не требуется, компилятор с радостью копирует символы, и все идет хорошо, в то время как на самом деле его дважды обманывали в течение процесса.

          Пример:

          По правилу шаловливых ручек, используйте тип «String» и заставляйте литералы работать.

          const s1 = 'äй';
          const s2: string = #$C3#$A4; // ä
          var s3;
          ...
            s3 := 'äöü';
          

          Note-icon.png

          Примечание: Строка UTF-8 может состоять из чисел, как это продемонстрировано для s2.

          • Литералы AnsiString/String работают как с директивой {$codepage utf8} / -FcUTF8 , так и без неё.
          • Литералы ShortString работоспособны только без указания директивы {$codepage utf8} / -FcUTF8. Вы можете сделать следующее:
          unit unit1;
          {$Mode ObjFPC}{$H+}
          {$modeswitch systemcodepage} // прекращает действие директивы -FcUTF8
          interface
          const s: string[15] = 'äй';
          end.
          

          В качестве альтернативы, возможно использовать строки shortstring с включенной директивой $codepage путем прямого присвоения кодов символов:

          unit unit1;
          {$Mode ObjFPC}{$H+}
          {$codepage utf8}
          interface
          const s: String[15] = #$C3#$A4; // ä
          end.
          
          • WideString/UnicodeString/UTF8String работают только с {$codepage utf8} / -FcUTF8.
          unit unit1;
          {$Mode ObjFPC}{$H+}
          {$codepage utf8}
          interface
          const ws: WideString = 'äй';
          end.
          

          Присвоение строкового литерала другим строковым типам, кроме простого «String», более мудрено.
          Смотрите таблицы, что работает, а что нет.

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

          Здесь работает означает правильную кодовую страницу и правильные кодовые точки. Кодовая страница 0 или кодовая страница 65001 — обе являются правильными, они означают UTF-8.

          Без {$codepage utf8} или переключателя компилятора -FcUTF8

          Тип String, исходник в UTF-8 Пример Const (в исходнике) Присвоение String Присвоение UTF8String Присвоение UnicodeString Присвоение CP1252String Присвоение RawByteString Присвоение ShortString Присвоение PChar
          const const s = ‘äöü’; working working wrong wrong wrong working working working
          String const s: String = ‘äöü’; working working working working working working working working
          ShortString const s: String[15] = ‘äöü’; working working working working wrong encoded working working not available
          UTF8String const s: UTF8String = ‘äöü’; wrong wrong wrong wrong wrong wrong wrong wrong
          UnicodeString const s: UnicodeString = ‘äöü’; wrong wrong wrong wrong wrong wrong wrong wrong
          String с объявленной кодовой страницей type CP1252String = type AnsiString(1252); wrong wrong wrong wrong wrong wrong wrong wrong
          RawbyteString const s: RawbyteString = ‘äöü’; working working working working to codepage 0 changed working working working
          PChar const c: PChar = ‘äöü’; working working working working wrong working working working

          С {$codepage utf8} или переключателем компилятора -FcUTF8

          Тип String, исходник в UTF-8 Пример Const (в исходнике) Присвоение String Присвоение UTF8String Присвоение UnicodeString Присвоение CP1252String Присвоение RawByteString Присвоение ShortString Присвоение PChar
          const const s = ‘äöü’; UTF-16 encoded working working working working working working working
          String const s: String = ‘äöü’; working working working working working working working working
          ShortString const s: String[15] = ‘äöü’; wrong wrong wrong wrong wrong wrong wrong not available
          UTF8String const s: UTF8String = ‘äöü’; working working working working working working working working
          UnicodeString const s: UnicodeString = ‘äöü’; working working working working working working working wrong
          String с объявленной кодовой страницей type CP1252String = type AnsiString(1252); working working working working working working wrong wrong
          RawbyteString const s: RawbyteString = ‘äöü’; working working working working to codepage 0 changed working working working
          PChar const c: PChar = ‘äöü’; wrong wrong wrong wrong wrong wrong wrong wrong

          Помните, что присваивание между переменными разных типов строк всегда работает благодаря их динамическому кодированию в FPC 3+.
          Данные конвертируются автоматически при необходимости.
          Только строковые литералы являются проблемой.

          Переход из более старых версий Lazarus + LCL

          Ранее (до 1.6.0) LCL поддерживал Unicode с выделенными функциями UTF8. Код не был совместим с Delphi.

          Сейчас многие старые приложения LCL продолжают работать без изменений. Однако имеет смысл очистить код, чтобы сделать его более простым и более совместимым с Delphi.
          Код, который читает/записывает данные с использованием кодировки системной кодовой страницы Windows, нарушается и должен быть изменен. (См. Чтение / запись текстового файла с кодовой страницей Windows).

          Явные функции преобразования необходимы только для ввода-вывода с данными кодовой страницы Windows или при вызове функций Windows Ansi. В противном случае FPC позаботится о автоматическом преобразовании кодировок. Для преобразования вашего старого кода предусмотрены пустые функции преобразования.

          • UTF8Decode, UTF8Encode — Почти все можно удалить.
          • UTF8ToAnsi, AnsiToUTF8 — Почти все можно удалить.
          • UTF8ToSys, SysToUTF8 — Почти все можно удалить. Теперь они являются пустышками и возвращают только свои параметры.

          Файловые функции в RTL теперь заботятся о кодировке имен файлов.
          Все (?) связанные с именем файла функции …UTF8() можно заменить на Delphi-совместимую функцию без суффикса UTF8.
          Например, FileExistsUTF8 можно заменить на FileExists.

          Большинство строковых функций UTF8…() можно заменить на совместимые с Delphi функции Ansi…(). Например, UTF8UpperCase() -> AnsiUpperCase().

          Теперь Unicode работает и в программах без GUI. Требуется только зависимость от LazUtils и размещение модуля LazUTF8 в разделе uses основного файла программы.

          Для исторической справки, это была старая поддержка Unicode в LCL:
          Old LCL Unicode Support

          Техническая реализация

          Что на самом деле происходит в системе Unicode? Эти 2 функции FPC вызываются в разделе ранней инициализации, устанавливая кодировку String по умолчанию в FPC в UTF-8:

           SetMultiByteConversionCodePage(CP_UTF8);
           SetMultiByteRTLFileSystemCodePage(CP_UTF8);
          

          В Windows функции UTF8…() в LazUTF8 (LazUtils) устанавливаются в качестве бэкэндов для строковых функций RTL Ansi…(). Таким образом, эти функции работают совместимым с Delphi способом.

          Кодовые страницы FPC

          Компилятор (FPC) поддерживает указание кодовой страницы, которое может быть записано через опцию командной строки -Fc (т.е. -Fcutf8) или эквивалентную директиве codepage (т.е. {$codepage utf8}). В этом случае, перед тем, как копировать байты, представляющие строковые константы в тексте вашей программы, компилятор будет интерпретировать все символьные данные в соответствии с указанной кодовой страницей. Есть две вещи, которые не стоит упускать из виду:

          • На платформах Unix, менеджер широких строк должен быть обязательно включен добавлением юнита cwstring в перечень uses. Без него программа не сможет правильно преобразовывать строковые данные во время исполнения.

          Менеджер широких строк добавляется по умолчанию в новом режиме UTF-8 RTL, однако это делает программу зависимой от libc и усложняет кросс-компиляцию.

          • Компилятор преобразует все строковые константы, содержащие символы, не относящиеся к ASCII, в константы типа widestring. Затем они автоматически преобразуются обратно в ansistring (либо во время компиляции, либо во время исполнения), но это может привести к искажениям, если вы попытаетесь смешать в одной строковой константе символы, напечатанные в тексте исходника и символы, заданные числовым представлением:

          Например:

          program project1;
          {$codepage utf8}
          {$mode objfpc}{$H+}
          {$ifdef unix}
          uses cwstring;
          {$endif}
          var
            a,b,c: string;
          begin
            a:='ä';
            b:='='#$C3#$A4; // #$C3#$A4 - закодированный в UTF-8 символ ä
            c:='ä='#$C3#$A4; // после не относящегося к  ascii 'ä' компилятор интерпретирует #$C3 в качестве отдельного widechar.
            writeln(a,b); // выводит ä=ä
            writeln(c);   // выводит ä=ä
          end.
          

          После компиляции и исполнения программа выведет:

          Причина в том, что после того как в строке обнаружен символ ä, как упоминалось выше, оставшаяся часть строковой константы, присваиваемой переменной ‘c’, будет обработана как widestring. В результате #$C3 и #$A4 интерпретируются как widechar(#$C3) и widechar(#$A4), вместо прямой трансляции в байтовое представление.

          Открытые вопросы

          • Символьные переменные в TFormatSettings (баг 27086): например: ThousandSeparator, DecimalSeparator, DateSeparator, TimeSeparator, ListSeparator. Эти поля должны быть заменены на строки для корректной поддержки UTF-8. Например, под Linux с установками LC_NUMERIC=ru_RU.utf8 разделитель тысяч состоит из двух байт nbsp/160.
            • Обход проблемы: использовать только одиночные символы пробелов вместо того, что должно быть на самом деле, как это сделано в патче на баг 27099

          Вызовы функций WinAPI в библиотеках FPC

          • Unit registry, TRegistry — этот unit использует Ansi функции Windows API и поэтому вам придётся пользоваться UTF8ToWinCP, WinCPToUTF8. Раньше для этого требовался вызов UTF8ToSys.
          • Все вызовы Windows функций с Ansi API в библиотеках FPC должны быть заменены версией W-API. Это в любом случае будет сделано для будущей поддержки UTF-16, поэтому никакого конфликта интересов нет. (прим. перев. — однако, эти действия означают декларированный отказ от дальнейшей поддержки версий Windows с неполной поддержкой Unicode — Windows 98, 95 и более ранних, а также некоторых мобильных и встроенных)
          • TProcess — под Windows TProcess FPC 3.0 поддерживает только системную кодовую страницу. Необходимо либо использовать TProcessUTF8 из unit utf8process или патчить FPC, см. баг 29136

          ToDo: Перечислить все относящиеся к багтрекеру FPC проблемы и патчи, которые могут эти проблемы решить.

          Будущее

          Целью проекта FPC является создание решения, базирующегося на Delphi-совместимом UnicodeString (UTF-16), но пока мы к этому не готовы. Потребуется длительное время для такой реализации.

          Реализацию LCL на базе UTF-8 в её имеющемся виде необходимо рассматривать как временное решение.
          В будущем, когда в FPC будет полная поддержка UnicodeString как в RTL, так и в FCL, проект Lazarus обеспечит решения для LCL, использующее эти возможности.
          В то же время целью является и сохранение поддержки UTF-8, несмотря на то, что это может потребовать изменения в строковых типах или чего-то ещё. Деталей пока не знает никто. Мы обязательно сообщим вам о них, когда станет известно…

          В сущности, LCL скорее всего придётся в будущем разделиться на две версии — одну для UTF-8, и другую для UTF-16.

          ЧаВо

          Что насчет режима DelphiUnicode?

          {$Mode delphiunicode} был добавлен в FPC 2.7.1 и похож на {$Mode Delphi} с {$ModeSwitch UnicodeStrings}. Смотрите следующий вопрос о ModeSwitch UnicodeStrings.

          Как насчет ModeSwitch UnicodeStrings?

          {$ModeSwitch UnicodeStrings} был добавлен в FPC 2.7.1 и определяет «String» как «UnicodeString» (UTF-16), «Char» как «WideChar», «PChar» как «PWideChar» и так далее. Это влияет только на текущий модуль. Другие модули, в том числе используемые этим модулем, имеют свое собственное определение «String». Многие строки и типы RTL (например, TStringList) используют 8-битные строки, которые требуют преобразования из/в UnicodeString, которые автоматически добавляются компилятором. LCL использует строки UTF-8. Рекомендуется использовать исходники в кодировке UTF-8 с или без «-FcUTF8».

          Почему бы не использовать UTF8String в Lazarus?

          Кратко: потому что FCL не использует его.

          Исчерпывающе:
          UTF8String определен в модуле system как

          UTF8String = type AnsiString(CP_UTF8);
          

          Компилятор всегда предполагает, что он имеет кодировку UTF-8 (CP_UTF8), которая является многобайтовой кодировкой (то есть 1-4 байта на кодовую точку). Обратите внимание, что оператор [] обращается к байтам, а не к символам или кодовым точкам. То же самое для UnicodeString, но только слова вместо байтов.
          С другой стороны, предполагается, что String во время компиляции имеет DefaultSystemCodePage (CP_ACP). DefaultSystemCodePage определяется во время выполнения, поэтому компилятор консервативно полагает, что String и UTF8String имеют разные кодировки. Когда вы присваиваете или комбинируете String и UTF8String, компилятор вставляет код преобразования. То же самое для ShortString и UTF8String.

          Lazarus использует FCL, который использует String, поэтому использование UTF8String добавит конверсии. Если DefaultSystemCodePage не UTF-8, вы теряете символы. Если это UTF-8, то нет смысла использовать UTF8String.

          UTF8String станет полезным, когда в конце концов появится FCL UTF-16.

          Почему UTF8String показывает странные символы, а String работает

          Например

          var s: UTF8String = 'ä';// с флагами по умолчанию (т.е. нет -Fc) это создает мусор
                                  // даже в системе UTF-8 Linux
          

          Вопрос: это ошибка? Ответ: Нет, потому что это работает как задокументировано.

          FPC игнорирует переменную LANG для создания в каждой системе одинакового результата. По историческим причинам/Delphi-совместимости он использует ISO-8859-1 по умолчанию. Lazarus предпочитает UTF-8.

          • Исходники UTF-8 работают со String, потому что
            1. FPC по умолчанию не добавляет код преобразования для обычных строковых литералов.
            2. Исходная кодовая страница равна кодовой странице времени выполнения. В Windows LazUTF8 устанавливает значение CP_UTF8.
          • UTF8String требует исходников UTF-8. Начиная с FPC 3.0 для UTF8String вы должны сообщать компилятору, что исходник является UTF8 (-FcUTF8, {$codepage UTF8} или сохранять файл как UTF-8 с BOM).

          Note-icon.png

          Примечание: Если вы сообщаете компилятору исходную кодировку UTF-8, он заменяет все строковые литералы ASCII этого модуля на UTF-16, увеличивая размер двоичного файла, добавляя некоторые служебные данные, и PChar для литералов требует явного преобразования. Вот почему Lazarus не добавляет его по умолчанию.

          Что случится, если я использую {$codepage utf8}?

          FPC имеет очень ограниченную поддержку UTF-8. Фактически, FPC поддерживает хранение литералов только как 8-битные строки с кодировкой «по умолчанию» или как widestrings (широкие строки). Поэтому любая кодовая страница не по умолчанию преобразуется в widestrings, даже если это системная кодовая страница. Например, большинство Linux/Mac/BSD используют UTF-8 в качестве системной кодовой страницы. Передача -Fcutf8 в компилятор сохранит строковый литерал как widestrings.

          Во время выполнения widestring литерал конвертируется. Когда вы присваиваете литерал AnsiString, widestring литерал преобразуется с помощью widestringmanager в кодировку системы. По умолчанию widestringmanager под Unix просто конвертирует widechars в символы, уничтожая любые символы не ASCII. Вы должны использовать widestringmanager, например, cwstring, чтобы получить правильное преобразование. Модуль LazUTF8 делает это.

          См. также

          Информация о Unicode, кодовых страницах, строковых типах и RTL в FPC.
          Обратите внимание, что эта информация не совсем полезна для системы Lazarus UTF-8, потому что с точки зрения FPC она является хаком и меняет кодовую страницу по умолчанию.
          Поддержка Юникода в FPC

          Понравилась статья? Поделить с друзьями:
        • Error identifier not found lazarus
        • Error identifier not found form1
        • Error identifier expected java
        • Error id returned 1 exit status что это
        • Error id 255 ecu address 92h error 6eh ивеко стралис