Перевести страницу

Создание приложений для науки и производства ещё не было таким простым

Операции с неизвестными типами параметров и неизвестным типом возврата

У многих операций типы параметров изначально не зафиксированы. Такие операции называются «контекстно-зависимыми». Контекстно-зависимая операция принимает операнды любого типа, но с рядом ограничений. Есть всего два основных вида таких операций: у одного вида тип какого-либо переданного параметра определяет остальные типы параметров, у другого вида типы параметров могут быть различными и независимы друг от друга. Это оказывает существенное влияние на автоматическое преобразование типов.


Для операций, у которых тип фиксированного (часто самого первого) параметра определяет типы остальных параметров, выполняются автоматические преобразования типов параметров. Разумеется, кроме того параметра, тип которого определяет остальные. На самой операции лежит ответственность за поддержку различных типов этого параметра, или останов программы, если полученный тип ей не поддерживается. В противном случае попытка выполнения операции над неподдерживаемым типом приведет к аварийному завершению всей системы. То же самое справедливо для операций, типы параметров которых могут быть различными. Автоматические преобразования над такими типами не выполняются, данные передаются операции как есть. Компилятор не может определить требуемый тип и выдать сообщение об ошибке, если преобразование невозможно. Такое сообщение выдается уже во время выполнения Ci-программы, что накладывает определенную ответственность на ее создателя. Однако поддержка различных типов данных внутри операций языка Ci не входит в рамки настоящего описания.


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

    float a; int b;

    puts (a * b);

будет корректно выполнено, поскольку будут произведены автоматические преобразования:

  • puts (вещественное-в-строку (a * (целое-в-вещественное b));

Из-за того, что первый параметр операции определяет тип второго параметра, в языке Ci не выполняется арифметическое правило “от перемены мест слагаемых сумма не изменяется” – во всяком случае, изменяется тип результата суммирования:

    float a 12.6;

    int b 1;

    floatstyle 1 FALSE;

    puts (a + b); ``напечатает вещественное число 13.6

    puts (b + a); ``напечатает целое число 13


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

    puts ((par# 0) * 2); `будет выдано сообщение об ошибке – невозможно определить тип`


Операция par# возвращает данное не определенного заранее типа. А тип первого параметра операции умножения также не определен. Для разрешения этой проблемы в Ci предусмотрено явное указание типа возвращаемого операцией значения:

    puts((int par# 0) * 2);


В таком случае операция par# вернет целочисленное значение первого параметра, который был передан в операцию call, а компилятор передаст его операции умножения и преобразует константу 2 в целое число для передачи вторым параметром. Явное указание корректно срабатывает только в случаях, когда компилятор выдает сообщение об ошибке с предложением его использовать. В остальных случаях тип определяется автоматически, а явное указание может дать не тот результат, который нужен, и его следует избегать.


Если же в качестве параметра указывается последовательность символов, и компилятор не находит подходящей переменной или литеральной константы, то он определяет тип следующим образом – если первый символ константы цифра или знак минус, то производится попытка преобразовать последовательность символов в вещественное число. При неуспехе выдается ошибка преобразования. Если же это другой символ, то последовательность символов считается строчной константой. Например:

    puts(100 * 2);

напечатает

    2.000000E2

поскольку константа 100 будет распознана, как вещественное число. Это определит тип другого параметра и возвращаемого результата. А при компиляции кода

    puts(a100 * 2);

если переменная a100 не объявлена ранее, будет выдано сообщение об ошибке «неизвестная переменная».