Переменные и пять встроенных типов

Пять встроенных типов Fortran — integer, real, complex, logical, character — это весь словарь, которым язык описывает данные.

Тип данных в Fortran определяет, какие значения может принимать переменная, сколько памяти она занимает и какие операции над ней допустимы. Встроенных (intrinsic) типов ровно пять.

Любая программа — это обработка данных, а данные нужно как-то описать. В отличие от языков с десятками встроенных типов, Fortran обходится пятью, и это не бедность, а сфокусированность: язык создавался для вычислений, поэтому в центре — числа. Этот урок знакомит со всеми пятью базовыми типами, показывает, как объявлять переменные, и объясняет, зачем в каждой программе обязательна строка implicit none. Освоив этот словарь, вы сможете описать данные почти любой численной задачи.

Немного истории: откуда взялись пять типов

Чтобы понять, почему типов именно пять и почему они такие, полезно вспомнить, в каком мире рождался язык. FORTRAN (от FORmula TRANslation — «перевод формул») создавался в IBM в 1954–1957 годах под руководством Джона Бэкуса как первый широко используемый язык высокого уровня. До него вычислительные машины программировали в машинных кодах, и каждая формула из учебника физики превращалась в десятки строк работы с регистрами. Главной целью Бэкуса было дать инженеру возможность записать A = B*C + D почти как на бумаге — и получить код, не уступающий по скорости ручной ассемблерной разработке. Эта родословная объясняет всё устройство языка: набор типов подбирался не «для общности», а под конкретную задачу — численное решение уравнений физики и инженерии.

Отсюда и состав. Инженеру нужны целые числа для счёта и индексации, вещественные — для измеримых величин, комплексные — потому что в электротехнике и теории колебаний они появляются естественно. Логический тип нужен для условий, символьный — чтобы подписать результат. Всё остальное (записи, указатели, абстрактные типы) добавили десятилетиями позже, когда язык эволюционировал через стандарты FORTRAN 66, 77, Fortran 90 и далее. Но это ядро из пяти типов осталось неизменным с конца 1950-х — редкий пример того, как удачно выбранная основа переживает полвека. Современный Fortran 2008/2018 — это уже язык с модулями, объектами и параллелизмом, но фундамент, который мы изучаем в этом разделе, тот же, что застали первые пользователи IBM 704.

Пять встроенных типов

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

ТипЧто хранитПример значения
integerцелые числа-7, 0, 42
realвещественные (с плавающей точкой)3.14, -0.5, 2.0e10
complexкомплексные числа(1.0, -2.0) = 1 − 2i
logicalистину или ложь.true., .false.
characterтекст (строки символов)"Fortran"

Числовые типы образуют ядро. integer — для счёта и индексов, real — для измеримых величин (масса, температура, скорость), complex — для задач, где числа естественно комплексны: электротехника, обработка сигналов, квантовая механика. logical хранит результат сравнений и управляет ветвлениями. character работает с текстом — заголовками, именами файлов, сообщениями. Никаких отдельных типов «байт», «строка», «булев массив» в базовом наборе нет; всё строится из этих пяти.

Особняком стоит complex, и стоит остановиться на нём отдельно. Встроенный комплексный тип — большая редкость среди языков программирования: в C его добавили только в стандарте C99 (через заголовок <complex.h>), в C++ он живёт как шаблон библиотеки std::complex, в Python — как отдельный объект complex. В Fortran же комплексное число — полноправный встроенный тип с самого рождения языка, наравне с целыми и вещественными. Это значит, что выражение z1 * z2 + z3 для комплексных переменных компилируется в прямой машинный код без вызовов библиотечных функций, а синтаксис литерала (1.0, -2.0) понимает сам компилятор. Для радиотехники, теории цепей, цифровой обработки сигналов и вычислительной физики это не косметика, а серьёзное преимущество в выразительности и скорости: формулы с комплексными амплитудами пишутся буквально как в учебнике.

Чем набор типов Fortran отличается от C и Python

Сравнение помогает увидеть характер языка. В C типов гораздо больше, и они «ближе к железу»: там есть char, short, int, long, long long, беззнаковые версии каждого, float, double, указатели. Программист на C думает о размере в байтах и о знаковости постоянно. Fortran сознательно прячет эти детали за абстракцией: вместо «короткого» и «длинного» целого вы выбираете нужный диапазон через параметр KIND (тема следующего урока), а компилятор подбирает физический размер. Философия здесь иная — не «дай мне 16-битное беззнаковое», а «дай мне целое, вмещающее числа до миллиарда».

Python стоит на противоположном полюсе. Там переменная вообще не имеет фиксированного типа: одно и то же имя сегодня указывает на целое, завтра — на строку, а целые числа автоматически растут до любой величины. Это удобно для скриптов, но дорого обходится в вычислениях: каждое число в Python — это объект с заголовком в памяти, и миллион сложений в цикле тратит время на разбор типов на каждом шаге. Fortran жёстко фиксирует тип переменной при объявлении именно ради скорости: зная, что x навсегда real, компилятор генерирует ровно одну машинную инструкцию сложения, без проверок. Статическая типизация — это договор с компилятором: вы отказываетесь от гибкости в обмен на предсказуемость и производительность, и для численных расчётов сделка почти всегда выгодна.

Объявление переменных

Переменную в современном Fortran объявляют в разделе описаний, до первого исполняемого оператора. Каноническая форма использует двойное двоеточие ::, отделяющее тип (с возможными атрибутами) от списка имён.

program declare
  implicit none
  integer :: count, index
  real :: temperature, pressure
  complex :: impedance
  logical :: is_ready
  character(len=20) :: name

  count = 10
  temperature = 36.6
  impedance = (50.0, -30.0)
  is_ready = .true.
  name = "Гершель"
  print *, count, temperature, is_ready, trim(name)
end program declare

Вывод:

          10   36.5999985  T Гершель

Несколько тонкостей видны сразу. Для character указывают длину: character(len=20) резервирует 20 символов; trim убирает хвостовые пробелы при печати. Логическое значение печатается как T или F. А температура 36.6 вывелась как 36.5999985 — это не ошибка, а фундаментальное свойство чисел с плавающей точкой, к которому мы вернёмся в уроке о KIND и точности. Двойное двоеточие :: обязательно, когда есть атрибуты или инициализация, и считается хорошим стилем всегда.

Зачем нужен implicit none

Это, возможно, самая важная строка во всём курсе. Без неё Fortran применяет неявную типизацию — древнее правило, по которому необъявленная переменная автоматически получает тип по первой букве имени: начинающиеся с I, J, K, L, M, N — целые, остальные — вещественные. Правило родилось ради экономии в эпоху, когда каждый символ на перфокарте был дорог, но сегодня это источник коварных багов.

program danger
  ! НЕТ implicit none — опасно!
  velocity = 10.0
  velosity = velocity * 2.0   ! опечатка: velosity вместо velocity
  print *, velocity           ! напечатает 10.0, а не 20.0
end program danger

Здесь опечатка velosity не вызывает ошибку: Fortran молча создаёт новую переменную. Программа компилируется, запускается и выдаёт неверный результат, который придётся искать часами. Строка implicit none превращает любую необъявленную переменную в ошибку компиляции, и опечатка ловится мгновенно. Правило простое: implicit none — первая строка после каждого program, module, subroutine и function. Без исключений.

Стоит понять, почему этот «костыль» вообще нужен — почему язык не отказался от неявной типизации совсем. Причина в обратной совместимости: миллионы строк рабочего кода, написанного с 1950-х по 1980-е, полагаются на старое правило, и сломать их новый стандарт не вправе. Fortran ценит совместимость почти религиозно: программа, корректная по стандарту 1977 года, обязана собираться современным компилятором. Поэтому неявную типизацию не убрали, а сделали отключаемой — implicit none это и есть осознанный отказ от наследия. В новом коде вы всегда его пишете; в старом — встречаете его отсутствие как метку «осторожно, легаси».

Цена пропущенного объявления в инженерной практике бывает огромной. В научном и инженерном Fortran-коде, который моделирует реакторы, прочность конструкций или климат, тихая опечатка в имени переменной не «роняет» программу с понятной ошибкой — она даёт правдоподобный, но неверный результат. Расчёт пройдёт, отчёт сформируется, а число окажется ошибочным, и заметить это можно слишком поздно. Именно поэтому в серьёзных проектах implicit none не рекомендация, а жёсткое требование стиля, проверяемое автоматически: ни один файл не попадает в репозиторий без этой строки. Привычку ставить её первой стоит выработать сразу — она экономит часы отладки и предотвращает ошибки, которые иначе не на чем поймать.

Сравнение с защитой от опечаток в других языках

Полезно увидеть, что та же проблема в разных языках решается по-разному. В Python присваивание velosity = ... тоже молча создаст новую переменную; опечатка станет ошибкой только при попытке прочитать несуществующее имя (вылетит NameError), а до тех пор баг невидим. В C объявлять переменные обязательно, и опечатка без объявления просто не скомпилируется — там «implicit none» встроен по умолчанию. Fortran занимает промежуточную позицию: по историческим причинам он допускает оба режима, и implicit none — переключатель, приводящий язык к строгости C.

Имена и правила именования

Имя переменной в Fortran начинается с буквы и состоит из букв, цифр и подчёркиваний; длина — до 63 символов. Регистр, как мы помним, не важен. Это даёт свободу выбирать осмысленные имена, и ею стоит пользоваться: kinetic_energy читается лучше, чем ke или загадочное x7. В численном коде, где формулы и так абстрактны, понятные имена переменных — главная линия обороны против ошибок.

program naming
  implicit none
  real :: kinetic_energy, mass, velocity
  mass = 2.0
  velocity = 3.0
  kinetic_energy = 0.5 * mass * velocity**2
  print *, "Кинетическая энергия:", kinetic_energy
end program naming

Вывод:

Кинетическая энергия:   9.00000000

Как работает под капотом

Что физически означает «объявить переменную»? Компилятор, встретив real :: temperature, выделяет под неё ячейку памяти нужного размера (для real по умолчанию — 4 байта, 32 бита) и связывает имя temperature с этим адресом. Размер зависит от типа: integer по умолчанию тоже 4 байта, complex — две вещественные части подряд (8 байт), logical — обычно 4 байта (хотя хранит один бит информации), character(len=20) — 20 байт под символы. Тип определяет не только размер, но и интерпретацию битов: одни и те же 32 бита компилятор прочитает как целое или как число с плавающей точкой по-разному, и именно объявление говорит ему, как именно.

Неявная типизация — это правило, встроенное в саму грамматику языка ещё в 1957 году: при первом упоминании необъявленного имени компилятор «на лету» создаёт переменную, угадывая тип по первой букве. implicit none — это директива, отключающая этот древний автоматизм, и потому она логически предшествует объявлениям.

Частые ошибки

  • Пропуск implicit none. Главная ошибка новичка. Без неё опечатки в именах не ловятся, и вы охотитесь за фантомными багами.
  • Объявление без длины для character. character :: name создаёт строку длиной всего 1 символ; для текста нужна character(len=N).
  • Ожидание точного real. Печать 36.6 как 36.5999985 пугает новичков; это нормальное свойство чисел с плавающей точкой, а не баг.
  • Объявление после исполняемого кода. Все описания обязаны идти до первого присваивания; иначе ошибка компиляции.
  • Загадочные однобуквенные имена. В численном коде это плодит ошибки; осмысленные имена резко повышают надёжность.

Итоги

  • В Fortran пять встроенных типов: integer, real, complex, logical, character.
  • Три числовых типа — ядро языка; complex встроен прямо в язык, что редкость.
  • Переменные объявляют через тип :: имена в разделе описаний, до исполняемого кода.
  • Для character указывают длину: character(len=20).
  • implicit none отключает неявную типизацию и обязателен в каждой программной единице.
  • Имена нечувствительны к регистру; выбирайте осмысленные имена ради надёжности.
Проверьте себя
1. Сколько встроенных (intrinsic) типов данных в Fortran?
AТри
BПять
CВосемь
DДвенадцать
2. Что произойдёт без implicit none, если в имени переменной сделать опечатку?
AОшибка компиляции
BFortran молча создаст новую переменную, и программа выдаст неверный результат
CПрограмма не запустится
DОпечатка автоматически исправится
3. Как правильно объявить строку на 20 символов?
Acharacter :: name
Bstring(20) :: name
Ccharacter(len=20) :: name
Dchar[20] name