Переменные и пять встроенных типов
Пять встроенных типов 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отключает неявную типизацию и обязателен в каждой программной единице.- Имена нечувствительны к регистру; выбирайте осмысленные имена ради надёжности.