Языки компьютерного программирования C и Pascal имеют схожие времена происхождения, влияния и цели. Оба они использовались для разработки (и компиляции) собственных компиляторов в самом начале своей жизни. Первоначальное определение Паскаля появилось в 1969 году, а первый компилятор - в 1970 году. Первая версия C появилась в 1972 году.
Оба являются потомками языковой серии АЛГОЛ . ALGOL представил поддержку языка программирования для структурированного программирования , где программы состоят из конструкций с одним входом и одним выходом, например if , while , for и case . Паскаль происходит непосредственно от АЛГОЛА W , в то время как он разделяет некоторые новые идеи с АЛГОЛОМ 68 . Язык C более косвенно связан с ALGOL, первоначально через B , BCPL и CPL , а затем через ALGOL 68 (например, в случае struct
и union
), а также через Паскаль (например, в случае перечислений const
, typedef
и логических значений). Некоторые диалекты Паскаля также включают черты C.
Задокументированные здесь языки - это Паскаль Никлауса Вирта , стандартизованный как ISO 7185 в 1982 году, и C Брайана Кернигана и Денниса Ритчи , стандартизованный в 1989 году. Причина в том, что обе эти версии представляют собой зрелую версию языка и еще и потому, что они сравнительно близки по времени. Функции ANSI C и C99 (более поздние стандарты C), а также функции более поздних реализаций Паскаля ( Turbo Pascal , Free Pascal ) не включены в сравнение, несмотря на улучшения надежности и функциональности, которые они предоставили.
Синтаксис
Синтаксически Паскаль гораздо больше похож на АЛГОЛ, чем Си . Английские ключевые слова сохраняются , где C использует символы пунктуации - Паскаль and
, or
и mod
где C использует &&
, ||
и %
, например. Однако C более похож на АЛГОЛ, чем Паскаль, в отношении (простых) объявлений, сохраняя синтаксис имени типа и имени переменной . Например, C может принимать объявления в начале любого блока, а не только внешнего блока функции.
Использование точки с запятой
Другое, более тонкое отличие - роль точки с запятой . В Паскале точки с запятой разделяют отдельные операторы в составном операторе; вместо этого в C они завершают оператор. В C они также являются синтаксической частью оператора (преобразование выражения в оператор). Эта разница проявляется в основном в двух ситуациях:
- в Pascal точка с запятой никогда не может стоять непосредственно перед
else
, тогда как в C она является обязательной, если не используется оператор блока - последний оператор перед
end
илиuntil
не обязательно должен сопровождаться точкой с запятой
В последней строке перед концом можно поставить лишнюю точку с запятой , тем самым формально вставив пустой оператор .
Комментарии
В традиционном C есть только /* block comments */
. Это поддерживается только некоторыми диалектами Паскаля, такими как MIDletPascal.
В традиционном Паскале есть и . Современный Паскаль, такой как Object Pascal (Delphi, FPC), а также современные реализации C допускают комментарии в стиле C ++.{ block comments }
(* block comments *)
// line comments
Идентификаторы и ключевые слова
Си и Паскаль различаются интерпретацией верхнего и нижнего регистра. C чувствителен к регистру , а Паскаль не является, таким образом , MyLabel
и mylabel
это разные имена в C , но идентичны в Паскале. В обоих языках идентификаторы состоят из букв и цифр с правилом, что первый символ не может быть цифрой. В языке C подчеркивание считается буквой, поэтому даже _abc является допустимым именем. Имена с начальным подчеркиванием часто используются для различения специальных системных идентификаторов в C.
И C, и Pascal используют ключевые слова (слова, зарезервированные для языка). Примеры: if , while , const , for и goto - ключевые слова, общие для обоих языков. В C основные встроенные имена типов также являются ключевыми словами (например, int , char ) или комбинациями ключевых слов (например, unsigned char ), тогда как в Pascal имена встроенных типов являются предопределенными обычными идентификаторами.
Определения, объявления и блоки
В Паскале определения процедур начинаются с ключевых слов процедура или функция, а определения типов - с типа . В C определения функций определяются синтаксическим контекстом, в то время как определения типов используют ключевое слово typedef
. Оба языка используют сочетание ключевых слов и знаков препинания для определений сложных типов; например, массивы определяются ключевым словом array в Pascal и пунктуацией в C, а перечисления определяются ключевым словом enum
C, но пунктуацией в Pascal.
В функциях Паскаля начало и конец ограничивают блок операторов (собственно), в то время как функции C используют "{" и "}" для ограничения блока операторов, которым необязательно предшествуют объявления. C (до C99) строго определяет, что любые объявления должны выполняться перед операторами в конкретном блоке, но позволяет блокам появляться внутри блоков, что является способом обойти это. Паскаль строго следит за тем, чтобы объявления происходили перед операторами, но позволяет инкапсулировать определения типов и функций, а не только объявления переменных, в определениях функций на любом уровне глубины.
Выполнение
Грамматики обоих языков примерно одинакового размера. С точки зрения реализации, основное различие между двумя языками состоит в том, что для синтаксического анализа C необходим доступ к таблице символов для типов, тогда как в Паскале такая конструкция только одна - присваивание. Например, фрагмент C X * Y;
может быть объявлением Y
объекта, тип которого является указателем X
, или оператором-выражением, которое умножает X
и Y
. Напротив, соответствующий фрагмент Паскаля var Y:^X;
по своей сути однозначен; для правильного синтаксического анализа таблица символов не требуется.
Простые типы
Целые числа
Паскаль требует, чтобы все объявления переменных и функций явно указывали их тип. В традиционном C имя типа может быть опущено в большинстве контекстов, а затем неявно предполагается тип по умолчанию int
(который соответствует integer
в Pascal) (однако такие значения по умолчанию считаются плохой практикой в C и часто помечаются предупреждениями).
С вмещает различные размеры и знаком и без знака режимы для целых чисел, используя модификаторы , такие как long
, short
, signed
, unsigned
и т.д. Точное значение результирующего целого типа является машинно-зависимым, однако, то , что может быть гарантировано, что int
по меньшей мере , 16 бит, long int
является не короче int
и short int
не длиннее int
.
Поддиапазоны
В Паскале аналогичное завершение выполняется путем объявления поддиапазона целых чисел (затем компилятор может выбрать выделение меньшего объема памяти для объявленной переменной):
введите a = 1 .. 100 ; b = - 20 .. 20 ; c = 0 .. 100000 ;
Эта функция поддиапазона не поддерживается C.
Основное, хотя и тонкое, различие между C и Pascal заключается в том, как они продвигают целочисленные операции. В Паскале результат операции определяется для всех целочисленных типов / поддиапазонов, даже если промежуточные результаты не помещаются в целое число. Результат не определен, только если он не помещается в целое число / поддиапазон в левой части присваивания. Это может означать искусственное ограничение диапазона целочисленных типов или может потребовать медленного выполнения для обработки промежуточных результатов: однако компилятор может использовать преимущества ограниченных поддиапазонов для создания более эффективного кода.
В C операнды сначала должны быть увеличены до размера требуемого результата: промежуточные результаты не определены, если они не попадают в диапазон продвинутых операндов. Если диапазон требуемого результата превышает диапазон операндов, это обычно приводит к медленному неэффективному коду, даже от хорошего оптимизирующего компилятора. Однако компилятор C никогда не требуется и не ожидает, что он будет обрабатывать промежуточные результаты, выходящие за пределы допустимого диапазона: ответственность за то, чтобы все промежуточные результаты попадали в диапазон операндов, лежит на программистах.
(Единственная) реализация C до стандарта, а также Small-C et al. позволили относительно свободно смешивать целочисленные типы и типы указателей .
Типы персонажей
В C тип символ , char
который является своего рода целое число , которое больше не является чем short int
,. Таким 'x'+1
образом, такие выражения , как и такие, как int i='i';
и заявления, являются совершенно законными char c=74;
.
Этот целочисленный характер char
(одного байта) ясно иллюстрируется такими объявлениями, как
беззнаковый символ uc = 255 ; / * общий лимит * / signed char sc = -128 ; / * общий отрицательный предел * /
Вопрос о том, char
следует ли рассматривать тип как signed
или unsigned
по умолчанию, зависит от реализации.
В Паскале символы и целые числа относятся к разным типам. Встроенный компилятор функционирует ord()
и chr()
может использоваться для приведения одиночных символов к соответствующему целочисленному значению используемого набора символов и наоборот. например, в системах, использующих набор символов ASCII ord('1') = 49
и chr(9)
является символом TAB.
Логические типы
В Паскале boolean - это перечислимый тип. Возможные значения boolean - false и true . Для преобразования в целое число используется ord :
i : = ord ( b ) ;
Стандартной функции для преобразования целого числа в логическое не существует , однако на практике преобразование выполняется просто:
b : = i <> 0 ;
C имеет бинарные операторы отношения (<,>, ==,! =, <=,> =), Которые можно рассматривать как логические в том смысле, что они всегда дают результат, равный нулю или единице. Поскольку все тесты (&&, ||,?:, If , while и т. Д.) Выполняются с помощью проверки нуля, ложь представляется нулем, а истина - любым другим значением.
Побитовые операции
C позволяет использовать побитовые операторы для выполнения логических операций. Следует проявлять осторожность, потому что семантика различается, когда операнды используют более одного бита для представления значения.
В Паскале есть еще один, более абстрактный, высокоуровневый метод работы с побитовыми данными, наборы . Наборы позволяют программисту устанавливать, очищать, пересекать и объединять побитовые значения данных вместо использования прямых побитовых операторов (которые также доступны в современном Паскале). Пример;
Паскаль:
Статус : = Статус + [ StickyFlag ] ; Статус : = Статус - [ StickyFlag ] ; если ( StickyFlag в статусе ), то ...(* В качестве альтернативы можно использовать побитовые операторы: *) Status : = Status или StickyFlag ; Статус : = Статус, а не StickyFlag ; если StickyFlag и Status = StickyFlag, то ...
C:
Статус | = StickyFlag ; Статус & = ~ StickyFlag ; if ( Status & StickyFlag ) { ...
Хотя битовые операции над целыми числами и операции над наборами можно считать аналогичными, если наборы реализованы с использованием битов, нет прямой параллели между их использованием, если не возможно нестандартное преобразование между целыми числами и наборами.
Примечание по реализации
Во время оценки выражения и на обоих языках логическое значение может храниться внутри как один бит, один байт, полное машинное слово, позиция в сгенерированном коде или как код условия в регистре состояния, в зависимости от машины. , компилятор и ситуация; эти факторы обычно более важны, чем скомпилированный язык.
Типы с плавающей запятой
C имеет менее строгую модель типов с плавающей запятой, чем Pascal. В C целые числа могут быть неявно преобразованы в числа с плавающей запятой и наоборот (хотя возможная потеря точности может быть отмечена предупреждениями). В Pascal, целые числа могут быть неявно преобразованы в real
, но преобразование real
к integer
(где информация может быть потеряна) должно быть сделано явным образом с помощью функций trunc()
и round()
, которые срезанным или круглая от фракции, соответственно.
Типы перечисления
И C, и Pascal включают типы перечисления. Пример Паскаля:
введите color = ( красный , зеленый , синий ) ; var a : color ;
Пример переменного тока:
enum color { красный , зеленый , синий }; перечислить цвет a ;
Однако поведение типов на двух языках сильно различается. В C red
становится синонимом 0, green
1, blue
2, и ничто не мешает присвоить переменной значение вне этого диапазона a
. Более того, a = a + 1;
в Паскале категорически запрещены операции вроде ; вместо этого вы бы использовали a := succ(a);
. В C перечисления можно свободно преобразовывать в целые числа и из них, но в Паскале для преобразования перечислимых типов в целые числа необходимо использовать функцию ord (), при обратном преобразовании должна использоваться операция приведения типов, как a := color(1)
для green
возврата значения.
Структурированные типы
Типы массивов
И C, и Pascal допускают использование массивов других сложных типов, включая другие массивы. Однако на этом сходство между языками заканчивается. Массивы C просто определяются базовым типом и количеством элементов:
int a [ РАЗМЕР ];
и всегда индексируются от 0 до SIZE-1 (т. е. по модулю SIZE).
В Паскале диапазон индексов часто определяется поддиапазоном (как описано выше для простых типов). Десять элементов
вар : массив [ 0 .. 9 ] из целого числа ;
будет проиндексирован 0..9 (как в C в этом случае). Индексы массива могут быть любым порядковым типом данных , но не только диапазонами:
введите TColor = ( красный , зеленый , синий ) ; (* перечисление *) RGB = массив [ TColor ] из 0 .. 255 ;вар картина : массив [ 1 .. 640 , 1 .. 480 ] из RGBвар палитра : массив [ байты , 0 .. 2 ] из байта
Строки, состоящие из n (> 1) символов, определяются как упакованные массивы с диапазоном 1..n.
Массивы и указатели
В выражениях C идентификатор, представляющий массив, рассматривается как постоянный указатель на первый элемент массива, таким образом, учитывая объявления int a[10]
и int *p;
присвоение, p = a
является допустимым и заставляет p и a указывать на один и тот же массив. Однако, поскольку идентификатор a
представляет собой постоянный адрес, a = p
он недействителен.
Хотя массивы в C фиксированы, указатели на них взаимозаменяемы. Эта гибкость позволяет C манипулировать массивом любой длины, используя один и тот же код. Это также оставляет ответственность программиста не писать за пределами выделенного массива, поскольку в язык не встроены проверки.
В Паскале массивы - это отдельный тип от указателей. Это делает возможной проверку границ массивов с точки зрения компилятора. Практически все компиляторы Паскаля поддерживают проверку диапазона как вариант компиляции . Возможность иметь массивы, которые меняют длину во время выполнения, и иметь возможность проверять их под управлением языка, часто называют «динамическими массивами». В Паскале количество элементов в каждом типе массива определяется во время компиляции и не может быть изменено во время выполнения программы. Следовательно, невозможно определить массив, длина которого каким-либо образом зависит от данных программы.
C имеет возможность инициализировать массивы произвольной длины. sizeof
Оператор может быть использован для получения размера статически инициализируется массив в коде C. Например, в следующем коде конечный индекс для цикла автоматически корректируется при изменении списка строк.
статический символ * словник [] = { "печать" , "из" , "в" , "текст" , "сообщение" }; static int listSize = ( sizeof ( список слов ) / sizeof ( список слов [ 0 ])); int i ;для ( я = 0 ; я < listSize ; я ++ ) ставит ( словник [ я ]); для ( я = listSize -1 ; я > = 0 ; я - ) ставит ( словник [ я ]);
В оригинальном Паскале нет ни инициализации массива (за исключением строк), ни средств определения произвольных размеров массива во время компиляции.
Один из способов реализации приведенного выше примера на Паскале, но без автоматической настройки размера:
const minlist = 1 ; maxlist = 5 ; maxword = 7 ;введите listrange = minlist .. maxlist ; wordrange = 1 .. maxword ; слово = запись содержания : упакованный массив [ wordrange ] из полукокса ; длина : конец диапазона слов ; словник = массив [ listrange ] из слова ; var i : целое число ; слова : список слов ; процедура CreateList ( var w : wordlist ) ; начать w [ 1 ] . содержание : = 'печать' ; w [ 1 ] . длина : = 5 ; w [ 2 ] . содержимое : = 'вне' ; w [ 2 ] . длина : = 3 ; w [ 3 ] . содержимое : = 'the' ; w [ 3 ] . длина : = 3 ; w [ 4 ] . содержимое : = 'текст' ; w [ 4 ] . длина : = 4 ; w [ 5 ] . содержание : = 'сообщение' ; w [ 5 ] . длина : = 7 ; конец ;begin CreateList ( слова ) ; for i : = minlist to maxlist сделать со словами [ i ] do WriteLn ( contents : length ) ; for i : = maxlist до минимального списка do со словами [ i ] do WriteLn ( contents : length ) end .
Струны
В обоих языках строка - это примитивный массив символов.
В Паскале строковый литерал длины n совместим с типом packed array [1..n] of char
. В C строка обычно имеет тип char[n]
.
Паскаль не поддерживает массивы переменной длины, поэтому любой набор подпрограмм для выполнения строковых операций зависит от конкретного размера строки. Стандартизированное теперь расширение «совместимого параметра массива» Паскаля решает эту проблему в значительной степени, и многие или даже большинство реализаций Паскаля поддерживают строки, родные для языка.
Строковые литералы C заканчиваются нулем ; то есть, завершающий нулевой символ в качестве конца-строк часового :
const char * p ; p = "дождь в Испании" ; / * завершается нулем * /
Для строковых переменных, хранящихся в массивах, необходимо вручную поддерживать нулевое завершение (это часто частично обрабатывается библиотечными подпрограммами).
В C отсутствует встроенная строка или присваивание массива, поэтому строка не передается в p, а вместо p указывается на постоянную строку в памяти.
В Паскале, в отличие от C, первый символьный элемент строки имеет индекс 1, а не 0 (что приводит к префиксу длины ). Это связано с тем, что Паскаль хранит длину строки в 0-м элементе массива символов. Если это различие не совсем понятно, оно может привести к ошибкам при портировании или попытке интерфейса объектного кода, созданного обоими языками.
Разработчик FreeBSD Пол-Хеннинг Камп , писавший в ACM Queue , позже назовет победу строк с завершающим нулем над строками с префиксом длины как «самую дорогостоящую однобайтовую ошибку». [1]
Типы записей
И C, и Паскаль могут объявлять типы « записи ». В языке C они называются «структурами».
struct a { int b ; char c ; };
введите a = запись b : целое число ; c : char ; конец ;
В Паскале мы можем использовать предложение « with
введите r = запись s : строка ; c : char ; конец ; var r1 : r ; начать с r1 действительно начать s : = 'foo' ; c : = 'b' ; конец ;
В C. нет функции, эквивалентной with .
В C может быть указана точная длина поля в битах:
STRUCT а { без знака Int б : 3 ; беззнаковый int c : 1 ; };
Объем используемой памяти зависит от характеристик (например, выравнивания слов) целевой системы.
Эта функция доступна в Паскале с использованием конструкции поддиапазона (3 бита дают диапазон от 0 до 7) в сочетании с ключевым словом pack :
тип a = упакованная запись b : 0 .. 7 ; c : 0 .. 1 ; конец ;
И C, и Pascal поддерживают записи, которые могут включать в себя разные поля, перекрывающие друг друга:
объединение a { int a ; float b ; };
тип а = запись случай логическое значение из ложно : ( : целое число ) ; истина : ( b : реальный ) конец ;
Оба языковых процессора могут выделять для этих записей ровно столько места, сколько необходимо для хранения наибольшего типа в объединении / записи.
Самая большая разница между C и Pascal заключается в том, что Pascal поддерживает явное использование «поля тегов» для языкового процессора, чтобы определить, осуществляется ли доступ к действительному компоненту вариантной записи:
тип а = запись случай д : булево из ложно : ( : целое число ) ; истина : ( b : реальный ) конец ;
В этом случае поле тега q должно быть установлено в правильное состояние для доступа к нужным частям записи.
Указатели
В C указатели могут указывать на большинство программных сущностей, включая объекты или функции:
int a ; int * b ; int ( * сравнить ) ( int c , int d ); int MyCompare ( int c , int d ); б = & а ; compare = & MyCompare ;
В C, поскольку массивы и указатели имеют близкую эквивалентность, следующее одинаково:
а = Ь [ 5 ]; а = * ( b + 5 ); а = * ( 5 + б ); а = 5 [ б ];
Таким образом, указатели часто используются в C как еще один метод доступа к массивам.
Для создания динамических данных, библиотечные функции malloc()
и free()
используются для получения и освобождения динамических блоков данных. Таким образом, динамическое распределение памяти не встроено в языковой процессор. Это особенно ценно, когда C используется в ядрах операционной системы или встроенных целях, поскольку эти вещи очень специфичны для платформы (а не только для архитектуры) и потребуют изменения компилятора C для каждой платформы (или операционной системы), на которой он будет использоваться.
В Паскале нет таких же указателей, как в C, но есть оператор косвенного обращения, который охватывает наиболее распространенное использование указателей C. Каждый указатель привязан к одному элементу динамических данных и может быть перемещен только путем присвоения:
введите a = ^ целое число ; var b , c : a ; новый ( б ) ; c : = b ;
Указатели в Паскале безопасны по типу; т.е. указатель на один тип данных может быть назначен только указателю того же типа данных. Также указатели никогда не могут быть присвоены переменным, не являющимся указателем. Арифметика указателей (общий источник ошибок программирования в C, особенно в сочетании с проблемами порядка байтов и независимыми от платформы размерами типов) в Паскале не разрешена. Все эти ограничения снижают вероятность ошибок, связанных с указателями, в Паскале по сравнению с C, но не предотвращают полностью недопустимые ссылки на указатели в Паскале. Например, ошибка времени выполнения произойдет, если на указатель будет сделана ссылка до его инициализации или после того, как он был удален.
Выражения
Уровни приоритета
Языки значительно различаются, когда дело доходит до оценки выражений, но в целом они сопоставимы.
Паскаль
- Логическое отрицание:
not
- Мультипликативный:
* / div mod and
- Добавка:
+ - or
- Относительный:
= <> < > <= >= in
C
- Унарный постфикс:
[] () . -> ++ --
- Унарный префикс:
& * + - ! ~ ++ -- (type) sizeof
- Мультипликативный:
* / %
- Добавка:
+ -
- Сдвиг:
<< >>
- Относительный:
< > <= >=
- Равенство:
== !=
- Побитовое и:
&
- Побитовый xor:
^
- Побитовое или:
|
- Логические и:
&&
- Логическое или:
||
- Условный:
? :
- Назначение:
= += -= *= /= %= <<= >>= &= ^= |=
- Оператор-запятая :
,
Печатать
Большинство операторов в Паскале служат нескольким целям, например, знак минус может использоваться для отрицания, вычитания или разницы наборов (в зависимости от типа и синтаксического контекста), >=
оператор может использоваться для сравнения чисел, строк или наборов и скоро. В C в большей степени используются специальные символы операторов.
Присваивание и тесты на равенство
В двух языках используются разные операторы для присваивания. Паскаль, как и ALGOL , использует оператор математического равенства =
для проверки равенства и символ :=
для присваивания, тогда как C, как и B , использует оператор математического равенства для присваивания. ==
Поэтому в C (и B) был введен новый символ для проверки равенства.
Это распространенная ошибка в C, вызванная либо неопытностью, либо простой опечаткой, - случайно поместить выражения присваивания в условные операторы, такие как if (a = 10) { ... }
. Код в фигурных скобках всегда будет выполняться, потому что выражение присваивания a = 10
имеет значение 10, которое не равно нулю и поэтому считается «истинным» в C; это отчасти потому, что C (и ALGOL) допускают множественное присваивание в форме, a = b = c = 10;
которая не поддерживается Паскалем. Также обратите внимание, что a
теперь имеет значение 10
, которое может повлиять на следующий код. Последние компиляторы C пытаются обнаружить эти случаи и предупредить пользователя, запрашивая менее двусмысленный синтаксис, например if ((a=10) != 0 ) { ... }
.
Такого рода ошибка не может произойти в Паскале, поскольку присваивания не являются выражениями и не имеют значения: использование неправильного оператора вызовет однозначную ошибку компиляции, а также маловероятно, что кто-то ошибочно примет :=
символ за проверку на равенство.
Примечательно, что условное выражение ALGOL в форме a := if a > b then a else b;
имеет эквивалент в C, но не в Паскале.
Проблемы реализации
Когда Никлаус Вирт разрабатывал Паскаль, желанием было ограничить количество уровней приоритета (в конце концов, меньше подпрограмм синтаксического анализа). Таким образом, операторы OR и исключающее OR обрабатываются как Addop и обрабатываются на уровне математического выражения. Аналогично, AND обрабатывается как Mulop и обрабатывается Term. Уровни приоритета:
Оператор элемента синтаксиса уровня 0 факторный литерал, переменная 1 знаковый множитель унарный минус, НЕ 2 член *, /, И 3 выражение +, -, ИЛИ
Обратите внимание, что существует только ОДИН набор правил синтаксиса, применимый к обоим типам операторов. Таким образом, согласно этой грамматике, такие выражения, как
x + (y, а не z) / 3
совершенно законны. И действительно, с точки зрения парсера. Паскаль не позволяет смешивать арифметические и логические переменные, и подобные вещи улавливаются на семантическом уровне, когда приходит время генерировать для них код, а не на уровне синтаксиса.
Авторы C придерживаются диаметрально противоположного подхода: они трактуют операторы как разные, и на самом деле в C не менее 15 уровней. Это потому, что C также имеет операторы '=', '+ =' и его родственники, '<<', '>>', '++', '-' и т. Д. Хотя в C арифметические и логические операторы рассматриваться отдельно, переменные не используются: логическая проверка может быть проведена для любого целочисленного значения.
Логические связки
В Паскале логическое выражение, основанное на определенном порядке оценки (возможно, через побочные эффекты в вызовах функций), более или менее рассматривается как ошибка. Компилятор Паскаля может свободно использовать любой порядок, который он предпочитает, и всегда должен оценивать все выражение целиком, даже если результат может быть определен путем частичной оценки.
В C, зависимость от булевых порядка оценки является совершенно законной, и часто систематически применяются с использованием &&
и ||
операторов вместе с операторами , такими как ++
, +=
, оператор запятой, и т.д. , &&
и ||
операторы тем самым функции как комбинации логических операторов и условных утверждений .
Оценка выражения короткого замыкания обычно считалась преимуществом для C из-за «проблемы оценки»:
var i : целое число ; : упакованный массив [ 1 .. 10 ] из полукокса ; ... я : = 1 ; while ( i <= 10 ) и ( a [ i ] <> 'x' ) do i : = i + 1 ; ...
Этот, казалось бы, простой поиск проблематичен в Паскале, потому что доступ к массиву a [i] был бы недействителен для i, равного 11. Есть несколько способов избежать этой проблемы. В следующем примере вводится логическая переменная, которая указывает, был ли найден целевой символ:
const strlen = 10 ; var i : целое число ; : упакованный массив [ 1 .. STRLEN ] из полукокса ; найдено : логическое ; ... я : = 1 ; найдено : = ложь ; пока не найдено и ( i <= strlen ) выполнить if ( a [ i ] = 'x' ) then found : = true else i : = i + 1 ; ...
Структуры управления
Заявления для построения управляющих структур примерно аналогичны и относительно похожи (по крайней мере, первые три).
Паскаль имеет:
- если cond, то stmt else stmt
- в то время как cond do stmt
- повторять stmt до cond
- для id : = expr to expr do stmt и для id : = expr downso expr do stmt
- case expr of expr : stmt ; ... выражение : stmt ; иначе: stmt ; конец
C имеет:
- если ( условие ) stmt else stmt
- в то время как ( cond ) stmt
- делать stmt while ( cond );
- for ( expr ; cond ; expr ) stmt
- переключатель ( выражение ) { case expr : stmt ; ... case expr : stmt ; по умолчанию: stmt }
Паскаль в его исходной форме не имел эквивалента default , но эквивалентное предложение else является распространенным расширением. В противном случае программистам на Pascal приходилось защищать операторы case с помощью такого выражения, как: если expr не в [A..B], то по умолчанию .
В C есть так называемые операторы раннего выхода break и continue , а также в некоторых Паскалях.
И C, и Pascal имеют оператор goto . Однако, поскольку в Паскале есть вложенные процедуры / функции, переходы могут выполняться от внутренней процедуры или функции к содержащей ее; это обычно использовалось для реализации исправления ошибок. C имеет эту возможность через ANSI C setjmp и longjmp . Это эквивалентно, но, возможно, менее безопасно, поскольку оно хранит информацию о программе, такую как адреса перехода и кадры стека, в доступной для программиста структуре.
Функции и процедуры
Подпрограммы Паскаля, возвращающие значение, называются функциями; подпрограммы, которые не возвращают значение, называются процедурами. Все подпрограммы в C называются функциями; Функции C, которые не возвращают значение, объявляются с типом возвращаемого значения void .
Процедуры Паскаля считаются эквивалентными функциям C "void", а функции Паскаля эквивалентны функциям C, которые возвращают значение.
Следующие два объявления в C:
int f ( int x , int y ); пустота k ( int q );
эквивалентны следующим объявлениям в Паскале:
функция f ( x , y : целое число ) : целое число ; процедура k ( q : целое число ) ;
В Паскале есть два разных типа параметров: передача по значению и передача по ссылке (VAR).
функция f ( var k : integer ) : целое число ; х : = f ( t ) ;
В C все параметры передаются по значению, но передачу по ссылке можно смоделировать с помощью указателей. Следующий сегмент похож на сегмент Паскаля выше:
int f ( int * k ); // функция принимает указатель как параметр x = f ( & t );
C позволяет функциям принимать переменное количество параметров, известных как вариативные функции .
int f ( int a , ...); f ( 1 , 2 , 3 , 4 , 5 );
Функция f()
использует специальный набор функций, которые позволяют ей обращаться к каждому из параметров по очереди.
Кроме того, Pascal имеет встроенные операторы ввода-вывода для обработки переменного количества параметров, например Writeln
. Паскаль позволяет процедуры и функции , которые будут вложены . Это удобно, чтобы разрешить переменные, которые являются локальными для группы процедур, но не глобальными. В C отсутствует эта функция, и локализация переменных или функций может быть выполнена только для компилирующего модуля, в котором переменные или функции были бы объявлены статическими .
C позволяет косвенно вызывать функции через указатель на функцию. В следующем примере оператор (*cmpar)(s1, s2)
эквивалентен strcmp(s1, s2)
:
#include int ( * cmpar ) ( const char * a , const char * b ); const char * s1 = "привет" ; const char * s2 = "мир" ;cmpar = & strcmp ; b = ( * cmpar ) ( s1 , s2 );
Паскаль также позволяет передавать функции и процедуры в качестве параметров функциям или процедурам:
процедура ShowHex ( i : целое число ) ; ... конец ;процедура ShowInt ( i : целое число ) ; ... конец ;процедура Demo ( процедура Show ( i : integer )) ; var j : целое число ; начало Показать ( j ) конец ;... Демо ( ShowHex ) ; Демо ( ShowInt ) ; ...
Препроцессор
В раннем C не было ни объявлений констант, ни объявлений типов, а язык C изначально определялся как требующий « препроцессора »; отдельная программа и проход, который обрабатывает определения констант, include и макросов , чтобы уменьшить использование памяти. Позже, с ANSI C, он получил функции определений констант и типов, а препроцессор также стал частью языка, что привело к синтаксису, который мы видим сегодня.
Константа Паскаля и определения типов встроены, но были программисты, использующие препроцессор также с Паскалем (иногда тот же самый, что использовался с C), конечно, не так часто, как с C. В C нет ни модульности программы, ни встроенных макросов. Однако он имеет простую низкоуровневую отдельную возможность компиляции (традиционно использующую тот же общий компоновщик, что и для языка ассемблера), в Паскале нет.
Тип экранирования
В C программист может проверить представление любого объекта на уровне байтов, указав на него char
указатель:
int a ; char * p = ( char * ) ( & a ); char c = * p ; // первый байт
Возможно, можно будет сделать что-то подобное в Паскале, используя неразборчивую вариантную запись:
var a : integer ; б : настоящий ; a2c : записать регистр логического значения false : ( a : целое число ) ; истина : ( b : реальный ) ; конец ; конец ; начать a2c . b : = b ; а : = а2с . а ; конец ;
Хотя приведение типов возможно в большинстве компиляторов и интерпретаторов Паскаля, даже в приведенном выше коде a2c.a и a2c.b не требуются никакими стандартами Паскаля для совместного использования одного и того же адресного пространства. Никлаус Вирт, разработчик языка Pascal, писал о проблематичной природе попытки экранирования шрифтов с использованием этого подхода:
«Большинство разработчиков Паскаля решили, что такая проверка будет слишком дорогой, увеличивая код и снижая эффективность программы. Как следствие, запись вариантов стала излюбленной функцией взлома системы типов для всех программистов, влюбленных в уловки, которые обычно превращаются в ловушки. и бедствия ".
Некоторые языки теперь специально исключают такие escape-последовательности, например Java, C # и собственный Oberon Вирта .
Файлы
В C файлы не существуют как встроенный тип (они определены в системном заголовке), и весь ввод-вывод осуществляется через вызовы библиотеки. В Pascal встроена обработка файлов.
Типичные операторы, используемые для выполнения ввода-вывода на каждом языке:
printf ( "Сумма:% d \ n " , x );
Writeln ( 'Сумма:' , x ) ;
Основное отличие состоит в том, что C использует «строку формата», которая интерпретируется для поиска аргументов функции printf и их преобразования, тогда как Паскаль выполняет это под управлением языкового процессора. Метод Pascal, возможно, быстрее, потому что не выполняется никакой интерпретации, но метод C очень расширяем.
Более поздние реализации и расширения Паскаля
Некоторые популярные реализации Паскаля включают практически все конструкции языка Си в Паскаль. Примеры включают приведение типов, возможность получить адрес любой переменной, локальной или глобальной, а также различные типы целых чисел со специальными свойствами продвижения.
Однако включение снисходительного отношения C к типам и преобразованиям типов может привести к тому, что Паскаль потеряет часть или всю свою безопасность типов. Например, Java и C # были созданы частично для решения некоторых предполагаемых проблем безопасности типов C и имеют «управляемые» указатели, которые нельзя использовать для создания недопустимых ссылок. В своей первоначальной форме (как описано Никлаусом Виртом ) Паскаль квалифицируется как язык с управляемыми указателями, примерно за 30 лет до Java или C #. Однако Паскаль, объединенный с C, потеряет эту защиту по определению. В целом, меньшая зависимость от указателей для основных задач делает его более безопасным, чем C.
Стандарт Extended Pascal расширяет Pascal для поддержки многих вещей, поддерживаемых C, чего не было в исходном стандарте Pascal, более безопасным способом. Например, типы схем поддерживают (помимо других применений) массивы переменной длины, сохраняя при этом типобезопасность обязательного переноса измерения массива вместе с массивом, позволяя автоматические проверки во время выполнения для индексов вне диапазона также для массивов с динамическим размером.
Смотрите также
- C , C ++
- Паскаль , Object Pascal , Free Pascal , Delphi , Oxygene
Заметки
- ↑ Камп, Поул-Хеннинг (25 июля 2011 г.), «Самая дорогая однобайтовая ошибка» , ACM Queue , 9 (7), ISSN 1542-7730 , получено 2 августа 2011 г.
дальнейшее чтение
- Кэтлин Дженсен и Никлаус Вирт: ПАСКАЛЬ - Руководство пользователя и отчет. Springer-Verlag, 1974, 1985, 1991, ISBN 3-540-97649-3 [1]
- Брайан Керниган , Деннис Ритчи : Язык программирования C . Также называется K&R - оригинальная книга о С.
- 1-й, Prentice Hall 1978; ISBN 0-13-110163-3 . Пре-ANSI C.
- 2-й, Prentice Hall 1988; ISBN 0-13-110362-8 . ANSI C.
- Никлаус Вирт: Комментарий к примечанию о динамических массивах в PASCAL 37-38, ACM SIGPLAN Notices, Volume 11, Issue 1, January 1976.
- Никлаус Вирт: Воспоминания о развитии Паскаля. 333-342, Уведомления ACM SIGPLAN, том 28, выпуск 3, март 1993 г.
- ИСО / МЭК 9899 . Официальный стандарт C: 1999 вместе с отчетами о дефектах и обоснованием.
- Подробный анализ преобразования C в Pascal
- Алан Р. Фейер, Нараин Х. Гехани: Сравнение языков программирования C и Pascal 73-92, ACM Computing Surveys, том 14, выпуск 1, март 1982 г.
- Сравнение и оценка языков программирования: Ada, C и Pascal , под ред. Алан Р. Фойер и Нараин Гехани, Prentice Hall, 1984. ISBN 0-13-154840-9
- Скотт Мейерс: Эффективный C ++ , 2-е изд., Addison-Wesley, 1998, ISBN 0-201-92488-9
- Винсент Хейворд: Сравнение анатомии языков программирования Pascal и C 50-60, ACM SIGPLAN Notices, Volume 21, Issue 5, May 1986.
- Паскаль для пользователей C