Типичный или безличный язык

Я изучаю C и язык ассемблера. Я заметил, что сборка - это язык без текста, по сравнению с C, который требует объявления типа данных до того, как данные могут быть обработаны. Но также я узнал, что даже код, написанный в C, сначала скомпилирован в код, написанный на сборке, а затем собран в объектный код. Таким образом, это означает, что объявление типа данных, которое мы используем в C, или любой язык высокого уровня предназначен только для удобства компилятора C. Они не имеют никакого особого отношения к объектным кодам. Это правильно?

То, что я собрал, - это объявление типа, указывающее компилятору, что все операции могут выполняться по данным, размеру данных (необходимых для хранения данных в сегменте данных), размер десятичных чисел max и min, которые можно сохранить. Могу ли я так сказать?

Есть ли другие преимущества объявления типа?

Ответ 1

В C у нас есть простая система типов, но она не особенно сложна, может быть (и часто на практике) обходиться с совершенно бесконтрольными бросками и т.д. (По этим причинам C часто называют "слабо типизированным", который плохо определен и обычно используется для изъятия языка, но, по крайней мере, говорит о том, что типы не так важны.) Размер, макет и выравнивание типов не фиксированы, хотя он, как правило, согласуется с одним и тем же компилятором ( версия) на той же платформе. int может быть 14 бит большой и т.д., Эти вещи не гарантируются (за исключением того, что для стандартов C требуется некоторое упорядочение между основными типами интегралов, например short не должно превышать int).

Программист не знает подробностей, но компилятор действительно и нужен. Например, точный код, сгенерированный для foo.y, где struct Foo { int x; short y; }; и struct Foo foo; зависит, например. на точных размерах int и short и на дополнении struct Foo, когда он компилируется до "берет адрес foo, добавьте смещение y в struct Foo) и используйте это". Даже struct Foo foo; требует точного знания struct Foo (и, рекурсивно, типов, из которых он состоит) - сгенерированный код должен знать точное sizeof(struct Foo) для резервирования правильного количества байтов в стеке? Аналогично, объявления типа необходимо знать, какие коды операций использовать для математики (iadd или fadd или дополнение? Должен ли один из операндов быть расширен и какой размер?), Сравнения, размер шага при выполнении арифметики указателя (p + n фактически добавляет n * sizeof(*p)) и т.д. Это также препятствует доступу к несуществующим членам (и, в добавлении, передаче значений к функциям, которые затем будут запускаться в эту проблему, т.е. несоответствие типа), но это больше похоже на удобный побочный эффект - компилятор считает это ошибкой, потому что не знал, какой код испускать, а не потому, что он считает, что программисты похожи на детей, которые должны быть просмотрены и сохранены в порядке.

В ассемблере (обычно - только вчера я прочитал о проекте в Microsoft Research, который разрабатывает типизированный, проверенный язык ассемблера для ОС, который защищен от определенных ошибок при построении), у вас на самом деле нет типов. У вас есть байты. Вы берете N байтов из некоторого места, делаете с ними кое-что и храните их в определенном месте. Да, регистры фиксируются на некоторый размер слова, а некоторые могут быть предназначены для специальных видов значений (например, выделенных регистров с плавающей запятой с 80 или более битами), но в основном вы можете хранить все, что угодно. Никто не мешает вам хранить 8 байт где-то, позже читая только последние 4 байта и добавляя их с вашим счетчиком циклов, чтобы сформировать адрес для сохранения возвращаемого значения в.

В других языках система типов намного прочнее, позволяя использовать огромный диапазон расширений, которые позволяют программировать более высокого уровня, например, абстрагировать точные типы (и, следовательно, их макет и ввод текста) и просто принимать любые типы, которые заполняют определенный контракт. Он позволяет использовать сигнатуры типов, такие как [a] -> a, которая является функцией, содержащей список, содержащий любой тип значения (если он однородный, например, список целых чисел, список строк, список списков символов и т.д.), и возвращает один из его элементов без "стирания" (например, приведение к void *) типа. (В зависимости от реализации он может фактически генерировать несколько реализаций, каждый для одного типа с известным макетом, для производительности - но это не просачивается к программисту.)

Ответ 2

Существует много того, что можно сказать о типах и их значении для программирования. И то, что вы видите на C, даже не является верхушкой айсберга. Скорее, это грязный снежный шар, который кто-то сбросил на кончик верхушки айсберга.:) Первые две страницы в следующей классической статье объясняют некоторые из основных достоинств систем типов:

http://www.lucacardelli.name/Papers/TypeSystems.pdf

Позвольте мне добавить две вещи.

Во-первых, существует разница между типизируемым языком и требованием (явным) объявлением типа. Некоторые современные языки, особенно из функционального лагеря, имеют сложные системы типов, которые все же не требуют, чтобы вы записывали один тип большую часть времени. Все типы выводятся компилятором.

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

Вот недавняя статья в CACM, в которой обсуждается (среди прочего) преимущества системы типов, найденной в функциональном языке OCaml:

http://cacm.acm.org/magazines/2011/11/138203-ocaml-for-the-masses/

Ответ 3

Да, вы довольно много прибили его. Ввод - просто удобная абстракция. Важно то, как вы используете необработанные биты. Типирование помогает заставить вас использовать эти биты по назначению.

Update

В некотором смысле, это помогает обеспечить правильность вашей программы, устраняя некоторые распространенные ошибки.
Скажем, у вас есть две переменные, char var1 = 'a' и int var2 = 10;. Если вы случайно попытались добавить var1 + var2, типизированный язык может вызвать ошибку. Если он не был напечатан, он может с радостью дать вам результат 107 и продолжить. Трудно отследить, откуда приходит 107, пока вы не поймете, что представление ASCII a равно 97.

Итак, в одном отношении, да, это гарантирует правильность вашей программы. Но очевидно, что существует много других ошибок (логических ошибок и т.п.), Которые нельзя предотвратить или идентифицировать, набрав только один.

Ответ 4

OR....

Более сложный безликий язык может дать вам результат

'a' + 7 

которая вообще не может быть ошибкой в ​​зависимости от определения оператора "+".