В 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 *
) типа.(В зависимости от реализации, он может на самом деле генерировать несколько реализаций, каждая для одного типа с известным макетом, для производительности - но это не проникает в программиста.)