Почему в Delphi 7 я могу присвоить значение константе?

StackOverflow https://stackoverflow.com/questions/48934

  •  09-06-2019
  •  | 
  •  

Вопрос

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

procedure TForm1.CalculateGP(..)
const
   Price : money = 0;
begin
   ...
   Price := 1.0;
   ...
end;

Так вот в новом проекте Delphi жалуется, что "левая часть не может быть назначена" - понятно!Но этот код компилируется в старом проекте.Итак, мой вопрос в том, почему?Есть ли переключатель компилятора, позволяющий переназначать константы?Как это вообще работает?Я думал, что константы были заменены их значениями во время компиляции?

Это было полезно?

Решение

Вам необходимо включить назначаемые типизированные константы.Проект -> Параметры -> Компилятор -> Назначаемые типизированные константы

Также вы можете добавить {$J+} или {$WRITEABLECONST ON} в файл pas, что, вероятно, лучше, поскольку оно будет работать, даже если вы переместите файл в другой проект.

Другие советы

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

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

Чтобы объяснить, почему исторически типизированные константы в ранних версиях Delphi и его предшественнике Turbo Pascal были доступны для записи (и, таким образом, по сути, инициализировали глобальные переменные), нам нужно вернуться во времена DOS.

DOS работает в реальном режиме, в терминах x86.Это означает, что программы имеют прямой доступ к физической памяти без каких-либо ММУ выполнение виртуально-физических отображений.Когда программы имеют прямой доступ к памяти, защита памяти не действует.Другими словами, если по любому заданному адресу имеется память, она доступна как для чтения, так и для записи в реальном режиме.

Таким образом, в программе Turbo Pascal для DOS с типизированной константой, значение которой выделяется по адресу в памяти во время выполнения, эта типизированная константа будет доступна для записи.Никакой аппаратный MMU не мешает программе писать в него.Точно так же, поскольку в Паскале нет понятия «константности», которое есть в C++, в системе типов нет ничего, что могло бы вас остановить.Многие этим воспользовались, поскольку в Turbo Pascal и Delphi в то время не было возможности инициализировать глобальные переменные.

Переходя к Windows, между адресами памяти и физическими адресами существует прослойка:блок управления памятью.Этот чип берет индекс страницы (смещенную маску) адреса памяти, к которому вы пытаетесь получить доступ, и ищет атрибуты этой страницы в ее памяти. таблица страниц.Эти атрибуты включают доступные для чтения, записи, а для современных чипов x86 — неисполняемые флаги.Благодаря этой поддержке можно пометить разделы .EXE или .DLL такими атрибутами, что, когда загрузчик Windows загружает исполняемый образ в память, он назначает соответствующие атрибуты страниц для страниц памяти, которые сопоставляются со страницами диска в этих разделах.

Когда появилась 32-битная версия компилятора Delphi для Windows, имело смысл создавать константно-подобные вещи. Действительно const, поскольку операционная система также имеет эту функцию.

  1. Почему:Потому что в предыдущих версиях Delphi типизированные константы можно было назначать по умолчанию, чтобы сохранить совместимость со старыми версиями, где они всегда были доступны для записи (от Delphi 1 до раннего Паскаля).
    Значение по умолчанию теперь изменено, чтобы сделать константы действительно постоянными…

  2. Переключатель компилятора:{$J+} или {$J-} {$WRITEABLECONST ON} или {$WRITEABLECONST OFF}
    Или в опциях проекта для компилятора:проверить назначаемые типизированные константы

  3. Как это работает:Если компилятор может вычислить значение во время компиляции, он заменяет const его значением повсюду в коде, в противном случае он сохраняет указатель на область памяти, содержащую значение, которую можно сделать доступной для записи или нет.
  4. см. 3.

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

  // Example implementation of the Singleton pattern.
  TSingleton = class(TObject)
  protected
    constructor CreateInstance; virtual;
    class function AccessInstance(Request: Integer): TSingleton;
  public
    constructor Create; virtual;
    destructor Destroy; override;
    class function Instance: TSingleton;
    class procedure ReleaseInstance;
  end;

constructor TSingleton.Create;
begin
  inherited Create;

  raise Exception.CreateFmt('Access class %s through Instance only', [ClassName]);
end;

constructor TSingleton.CreateInstance;
begin
  inherited Create;

  // Do whatever you would normally place in Create, here.
end;

destructor TSingleton.Destroy;
begin
  // Do normal destruction here

  if AccessInstance(0) = Self then
    AccessInstance(2);

  inherited Destroy;
end;

{$WRITEABLECONST ON}
class function TSingleton.AccessInstance(Request: Integer): TSingleton;
const
  FInstance: TSingleton = nil;
begin
  case Request of
    0 : ;
    1 : if not Assigned(FInstance) then
          FInstance := CreateInstance;
    2 : FInstance := nil;
  else
    raise Exception.CreateFmt('Illegal request %d in AccessInstance', [Request]);
  end;
  Result := FInstance;
end;
{$IFNDEF WRITEABLECONST_ON}
  {$WRITEABLECONST OFF}
{$ENDIF}

class function TSingleton.Instance: TSingleton;
begin
  Result := AccessInstance(1);
end;

class procedure TSingleton.ReleaseInstance;
begin
  AccessInstance(0).Free;
end;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top