О влиянии директивы {$H+} при работе с файлами

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

О влиянии директивы {$H+} при работе с файлами

Сообщение Kubanych » 30.12.2009 20:27:00

Здравствуйте!
Всех с наступающим новым годом.
Имеется такой код в Lazarus (FPC):
Код: Выделить всё
program create_files;
{$mode objfpc}{$H+}
uses
  CRT, FileUtil, SysUtils;
type
  manager= record
  name: string;
  comp: integer;
end;
var
  company: manager;
  fmanager: File of manager; // Файловая переменная
  k: integer;
  n: integer;
begin
  AssignFile(fmanager,'File_manager.dat');
  {Проверка существования файлов. Если файлы
  существуют, то они открываются для дозаписи.
  Если нет, то создаются новые пустые файлы}
  if not FileExists('File_manager.dat') then
    Rewrite(fmanager)
  else
  Reset(fmanager);
  Seek(fmanager, System.FileSize(fmanager));
  while not Eof(fmanager) do
     Read(fmanager, company);
  writeln(UTF8ToConsole('Введите количество менеджеров компании'));
  readln(n);
  with company do
  begin
    for k:= 1 to n do
    begin
      writeln(UTF8ToConsole('Введите фамилию'));
      readln(name);
      writeln(UTF8ToConsole('Введите количество реализованных им компьютеров'));
      readln(comp);
      Write(fmanager, company); // запись в файл
    end;
  end;
  writeln(UTF8ToConsole('Информация на диск записана'));
  CloseFile(fmanager);
  writeln(UTF8ToConsole('Нажмите любую клавишу'));
  readkey;
end.

Если дать директиву компилятора {$mode objfpc}{$H+}, то почему-то файл не создается, точнее создается, но, по моему, пустой. Никаких ошибок не выдается. Но есть другая программа, которая должна читать созданный файл и выводить на экран в определенном виде. Эта программа вылетает с ошибкой:
Project manager.exe raised exception class 'External: SIGSEGV'

Но, если эту директиву убрать совсем или дать в виде {$mode objfpc}{$H-}, то файл создается и вторая программа ее нормально обрабатывает.
Никто не знает, почему {$H+} так действует?
Можно конечно просто убрать эту директиву, но хочется понять в чем дело.
Привожу также код второй программы:
Код: Выделить всё
program manager_computer;
{$mode objfpc}{$H-}
uses
  CRT, FileUtil, SysUtils, LCLProc;
type
  manager= record
  name: string;
  comp: integer;
end;
var
  company: manager;
  fmanager: File of manager; // Файловая переменная
  sum, cost, prem, k: integer;
  n: integer;
  sumc, sumv, sump, sum1: integer;
  sname: string[18];
begin
  {При необходимости укажите полный путь
  к файлам или скопируйте эти файлы в папку
  с данным проектом или сохраните сам проект
  в папке, где создан проект create_files.lpr }
  if not FileExists('File_manager.dat') then
  begin
    writeln(UTF8ToConsole('Файлы не существуют'));
    writeln(UTF8ToConsole('Сначала создайте их'));
    writeln(UTF8ToConsole('Нажмите любую клавишу'));
    readkey;
    exit;
  end;
  AssignFile(fmanager,'File_manager.dat');
  Reset(fmanager);
  n:= System.FileSize(fmanager);
  ClrScr;
  GoToXY(6, 1);
  write(UTF8ToConsole('Сведения о реализации компьютеров'));
  GoToXY(14, 2);
  write(UTF8ToConsole('за январь 2009 г.'));
  GoToXY(1, 3);
  write('------------------------------------------------');
  GoToXY(1, 4);
  write(UTF8ToConsole(' Фамилия           Количество Выручка Премия'));
  GoToXY(1, 5);
  write('------------------------------------------------');
  cost:= 1000; // стоимость компьютера
  prem:= 25;   // размер премии
  sumc:= 0;    // Общее количество компьютеров
  sumv:= 0;    // Общая сумма выручки
  sump:= 0;    // Общая сумма премии
  k:= 0;       // Отслеживает текущую строку на экране
  with company do
  begin
    while not Eof(fmanager) do
    begin
      Read(fmanager, company);
      sum:= comp * cost;  // сумма выручки для одного менеджера
      sum1:= comp * prem; // сумма премиальных для одного менеджера
      sumc:= sumc + comp;
      sumv:= sumv + sum;
      sump:= sump + sum1;
      sname:= copy(name, 1, 18);
      writeln;
      writeln(sname);
      GoToXY(24, k + 6);
      write(comp);
      GoToXY(32, k + 6);
      write(sum);
      GoToXY(40, k + 6);
      write(sum1);
      k:= k + 1;
    end;
  end;
  GoToXY(1, n + 6);
  write('------------------------------------------------');
  GoToXY(17, n + 7);
  write(UTF8ToConsole('Итого:'));
  GoToXY(24, n + 7);
  write(sumc);
  GoToXY(32, n + 7);
  write( sumv);
  GoToXY(40, n + 7);
  write(sump);
  GoToXY(1, n + 9);
  writeln(UTF8ToConsole('Нажмите любую клавишу'));
  CloseFile(fmanager);
  readkey;
end.
Kubanych
новенький
 
Сообщения: 73
Зарегистрирован: 15.10.2008 10:02:18

Re: О влиянии директивы {$H+} при работе с файлами

Сообщение Sergei I. Gorelkin » 31.12.2009 00:11:15

В состоянии {$h-} тип string - это массив символов, а в состоянии {$h+} - указатель, который просто так записать в типизированный файл нельзя. По хорошему, компилятор должен отказываться от такой конструкции. Дельфи отказывается, FPС нет - поэтому команда получает очередной новогодний подарок http://bugs.freepascal.org/view.php?id=15447 :)
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: О влиянии директивы {$H+} при работе с файлами

Сообщение Kubanych » 31.12.2009 07:06:58

Значит, если этой директивы вообще нет, то компилятор по умолчанию считает string массивом символов, т.е. то, к чему мы все привыкли и чему нас учили. Следовательно, эту директиву нужно всегда убирать, кроме тех редких(?!) случаев, когда string нужно рассматривать как указатель?
Kubanych
новенький
 
Сообщения: 73
Зарегистрирован: 15.10.2008 10:02:18

Re: О влиянии директивы {$H+} при работе с файлами

Сообщение Odyssey » 31.12.2009 08:54:29

Нет, как правило всё наоборот. Дело в том, что в режиме массива символов длина строки ограничена 255 байтами (т.е. символами ANSI). Собственно это и позволяет писать такие строки в типизированный файл. Но чаще всего приходится работать со строками, длина которых существенно больше 255 символов, поэтому директиву чаще всего включают. В режиме совместимости с Delphi она включена по умолчанию.
Со включенной директивой вышеприведённую программу тоже можно заставить работать, если вместо
Код: Выделить всё
manager= record
  name: string;
  comp: integer;
end;

в обеих программах написать
Код: Выделить всё
manager= record
  name: string[255];
  comp: integer;
end;
Odyssey
энтузиаст
 
Сообщения: 580
Зарегистрирован: 29.11.2007 17:32:24


Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1

Рейтинг@Mail.ru