C строго типизирован?


88

Процитирую Википедию :

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

Есть ли более точный ответ?


188
Для программиста на C строгая типизация означает более сильное нажатие на клавиши.
Дэн Дайер

2
C находится на слабой стороне в процессе набора текста. Но с обеих сторон есть достаточно пунктов, о которых можно поспорить. Пока вы на нем, вы можете также спросить (vi или emacs, netbeans или eclipse и т. Д.)
Cervo

4
Состояние дел в Википедии было настолько плохим, что я почувствовал необходимость отредактировать несколько страниц Википедии. Может, сейчас дела обстоят немного лучше. Может быть.
Норман Рэмси,

40
Касательно: Комментарий Дэна (отдавая должное) Книга Питера ван дер Линдена «Эксперт по программированию на C» содержит следующую строку: «По сей день многие программисты на C считают, что« строгая типизация означает лишь дополнительную нагрузку на клавиатуру ».
Александрос Гезерлис 02

Очень хороший вопрос !!!
Destructor

Ответы:


154

Термины «строго типизированный» и «слабо типизированный» не имеют общепринятого технического значения. Термины, которые имеют четко определенное значение:

  • Динамически типизированный означает, что типы присоединяются к значениям во время выполнения, и попытка смешивания значений разных типов может вызвать «ошибку типа времени выполнения». Например, если в схеме вы попытаетесь добавить единицу к true, написав, (+ 1 #t)это вызовет ошибку. Вы столкнетесь с ошибкой, только если попытаетесь выполнить ошибочный код.

  • Статически типизированный означает, что типы проверяются во время компиляции, а программа, не имеющая статического типа, отклоняется компилятором. Например, если в ML вы попытаетесь добавить единицу к true путем записи 1 + true, программа будет отклонена с (возможно, загадочным) сообщением об ошибке. Вы всегда получаете сообщение об ошибке, даже если код может никогда не быть выполнен.

Разные люди предпочитают разные системы отчасти в зависимости от того, насколько они ценят гибкость и насколько они беспокоятся об ошибках времени выполнения.

Иногда «строго типизированный» используется в широком смысле для обозначения «статически типизированный», а «слабо типизированный» неправильно используется для обозначения «динамически типизированный». Термин «строго типизированный» лучше использовать в том случае, если «нельзя обойти или подорвать систему типов», тогда как «слабо типизированный» означает «в системе типов есть лазейки». И наоборот, большинство языков со статическими системами типов имеют лазейки, в то время как многие языки с системами динамических типов не имеют лазеек.

Ни один из этих терминов никак не связан с количеством неявных преобразований, доступных в языке.

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

Я написал больше о статической и динамической типизации в статье, почему-интерпретируемые-языки-в основном-утиные-пока-скомпилированы-имеют-строгую-типизацию .


2
Откуда вы взяли определения, которые вы предлагаете для сильной / слабой типизации (лазейки)?
Sydius

2
Зачем вам нужна «лазейка» в среде динамического набора текста?
Крис Конвей,

4
@Sydius: За последние 20 лет большую часть времени провел в общении с людьми, которые проектируют, создают и анализируют языки программирования и системы типов. Это моя оплачиваемая работа :-)
Норман Рэмси

@Chris: Я никогда не видел динамически типизированного языка с «лазейкой». Обычно лазейка используется для работы с системой времени выполнения или ОС, например, берет необработанный адрес и преобразует его в указатель на значение языка с хорошим поведением. Вы могли бы сделать это в динамическом режиме, но я не знаю ни одной попытки.
Норман Рэмси,

1
@NormanRamsey Я думаю, что Крис имел в виду:whereas "weakly typed" means "there are loopholes in the type system
Нир Альфаси

23

Трудно разделить каждый язык на «слабо» или «строго» типизированный - это скорее континуум. Но по сравнению с другими языками C довольно сильно типизирован. Каждый объект имеет тип во время компиляции, и компилятор сообщит вам (громко), если вы делаете что-то с объектом, что его тип не позволяет вам сделать. Например, вы не можете вызывать функции с неправильными типами параметров, получать доступ к несуществующим членам структуры / объединения и т. Д.

Но есть несколько слабых мест. Одна из основных слабостей - это приведение типов: они по сути говорят, что вы собираетесь возиться с типами объектов, и компилятор должен молчать (когда это возможно). void*еще одна слабость - это общий указатель на неизвестный тип, и когда вы их используете, вы должны быть особенно осторожны, чтобы поступать правильно. Компилятор не может статически проверить большинство случаев использования void*. void*также может быть преобразован в указатель на любой тип без приведения (только в C, а не в C ++), что является еще одним недостатком.


Хороший ответ, хотя меня беспокоит "приведение типов ... и компилятор должен быть тихим". Приведение типа не похоже на отключение предупреждения, оно фактически меняет интерпретацию значения, на которое ссылаются.
Высокий Джефф,

15
Вы путаете "статичность" и "сильный" в отношении набора текста. Эти два понятия не зависят друг от друга.
bendin

1
Деннис Ричи (автор C) назвал C «строго типизированным и слабо проверенным»
TimZaman

11

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

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

Так:

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

Так является ли Java статически типизированной? Да, потому что его система типов не позволяет вычитать строку из числа. Нет, потому что это позволяет делить на ноль. Вы можете предотвратить деление на ноль во время компиляции с помощью системы типов. Например, создав числовой тип, который не может быть нулем (например, NonZeroInt), и разрешить деление только на числа, которые имеют этот тип.

Итак, C строго типизирован или слабо типизирован? C строго типизирован, потому что система типов запрещает некоторые ошибки типов. Но он слабо типизирован в других случаях, когда неясно, что происходит (и система типов вас не защищает).


Мне нравится, когда вы сочетаете динамику и статику как формы сильного и слабого. Однако я не уверен, что понимаю вашу точку зрения о статически типизированных системах, которые перестают делиться на ноль. Если мой статически типизированный intполучает значение от пользователя, аргументов командной строки или файла, компилятор ничего не может сделать, чтобы помешать этому быть нулем!
Rikki

1
Существуют системы статических типов, которые предотвращают это, но большинство языков либо слабо, либо динамически "типизированы" относительно деления на ноль, потому что это неопределенное поведение (C) или они вызывают исключение (Java).
Жюль

11

C считается слабо типизированным, потому что вы можете преобразовать любой тип в любой другой с помощью приведения без ошибки компилятора. Вы можете узнать больше о проблеме здесь .


2
здесь Википедия вводит в заблуждение. C строго типизирован, типы очень допустимы, и компилятор заблокирует их, если вы ошиблись, однако C также предоставляет возможности для обхода этого. Сравните с такими языками, как BCPL, которые имеют только байтовый тип.
gbjbaanb

12
Слабая типизация не означает, что в языке нет типов, это просто означает, что типы можно неявно приводить от одного типа к другому. Сравните с Python, языком со строгой типизацией, в котором вы должны явно преобразовывать типы с помощью вызовов функций.
mipadi

Способность преобразовать объект в C также способствует тому, чтобы он был слабым типом. ?? Я сомневаюсь в этом навсегда
Сурадж Джайн

8

C более строго типизирован, чем Javascript, и менее строго типизирован, чем Ada.

Я бы сказал, что это больше относится к строго типизированной стороне континуума. но кто-то другой может не согласиться (даже если он ошибается).

Как это для окончательного?


Это был несколько насмешливый ответ. Но уточните ошибку.
Майкл Берр,

1
Javascript строго типизирован. Он просто не типизирован статически. Все проверки типов происходят во время выполнения (динамические, а не статические), но они действительно происходят и предотвращают повреждение памяти (один из аспектов строгой типизации).
bendin

5
Что ж, как показывает очень хороший ответ Норма Рэмси, «строго типизированный» и «слабо типизированный» - не очень хорошо определенные термины. Кроме того, поскольку Javascript строго типизирован, некоторые могут подумать, что ("4" / ​​"2"), являющееся допустимым выражением Javascript, может указывать на иное.
Майкл Берр,

5

C считается статически типизированным (вы не можете изменять переменную с int на float). Как только переменная объявлена, она так и застревает.

Но он считается слабо типизированным, потому что типы можно перевернуть.

Что такое 0? '\ 0', ЛОЖЬ, 0,0 и т. Д.

на многих языках нельзя использовать IF (переменная), потому что условия будут принимать только логические значения из логических выражений. Они более строго типизированы. То же самое относится к переходу между символами и целыми числами.

в основном c имеет два основных простых типа данных, целые числа и числа с плавающей запятой (хотя и с различной точностью). Все остальное логические значения, перечисления (не простые, но подходящие) и т.д. реализованы как одни из них. Даже символы в основном целые.

Сравните с другими языками, где есть строковые типы, типы перечислений, которые могут быть присвоены только определенным значениям, логические типы, где могут использоваться только выражения, которые генерируют логические значения или истина / ложь.

Но вы можете возразить, что по сравнению с Perl C сильно типизирован. Так что это один из тех известных аргументов (vi vs emacs, linux vs windows и т. Д.). C # типизирован сильнее, чем C. В принципе, можно спорить в любом случае. И ваши ответы, вероятно, пойдут в обе стороны :) Также некоторые учебники / веб-страницы скажут, что C слабо типизирован, а некоторые скажут, что C строго типизирован. Если вы зайдете в Википедию, в записи C написано «частично слабая типизация». Я бы сказал, что по сравнению с Python C слабо типизирован. Итак, Python / C #, C, Perl на континууме.


Пожалуйста, объясните свое мнение о том, что Perl менее строго типизирован, чем C.
user51568

print "Testing" + 0 # perl выполнит 0; $ var = "строка"; $ var = 1; $ var = 123,4; Что это за переменная?
Cervo

В C char * test = "testing"; printf (тестирование + 0); по-прежнему будет строкой, просто в C индекс изменится, если вместо нуля я использую число. Он все еще довольно слабый, но немного сильнее, чем perl. char * test; test = 0; test = 123,4; test = "c"; ... мой компилятор выдает ошибки
Cervo

ошибка говорит о том, что требуется приведение. Тем не менее, это немного сильнее проверки типов, чем Perl, поэтому в целом я должен сказать, что C более строго типизирован, чем Perl. Вы все равно можете пойти test = (char *), а затем использовать 0, 123.4, 'C' и т. Д. Но просто сделать это - ошибка.
Cervo

4

Здесь много хороших ответов. Я хочу поднять важный момент из Real World Haskell :

Полезно знать, что многие языковые сообщества имеют свои собственные определения «сильного типа». Тем не менее, мы будем говорить кратко и широко о понятии силы в системах типов.

(вырезать)

Фейерверк вокруг систем шрифтов берет свое начало в обычном английском, где люди придают понятие ценности словам «слабый» и «сильный»: мы обычно думаем о силе лучше, чем о слабости. Гораздо больше программистов говорят на простом английском, а не на академическом жаргоне, и довольно часто ученые бросают курить в любую систему шрифтов, которая не соответствует их воображению. Результатом часто становится это популярное времяпрепровождение в Интернете, огненная война.

Итак, посмотрите ответы на C и C ++, но помните, что «сильный» и «слабый» не соответствуют «хорошему» и «плохому».


4

По словам Денниса Ричи ( создателя C ) и Брайана Кернигана, C не является строго типизированным языком. Следующие строки взяты из книги Язык программирования C, страница 3, параграф 5.

C не является строго типизированным языком, но по мере его развития его проверка типов была усилена.


3

На мой взгляд, C / C ++ строго типизированы. Типы хаков, которые позволяют преобразовывать типы (void *), существуют из-за близости C к машине. Другими словами, вы можете вызывать команды ассемблера из Паскаля и манипулировать указателями, а Паскаль по-прежнему считается строго типизированным языком. Вы можете вызывать исполняемые файлы ассемблера и C из Java через JNI, но это не делает Java слабо типизированным.

В C просто «встроен» ассемблер с необработанными указателями и тому подобным.


3

Термин строго типизированный не имеет согласованного определения. Поэтому, если вы не определите, что вы имеете в виду под «строго типизированным», на ваш вопрос невозможно ответить.

По моему опыту, термины «строго типизированный» и «слабо типизированный» используются исключительно троллями, потому что их отсутствие определений позволяет троллям переопределять их в середине аргумента, чтобы удовлетворить их повестку дня. Эти термины бесполезны, если не считать начала боевых действий.

Вы также можете взглянуть на Каковы ключевые аспекты строго типизированного языка? здесь, в StackOverflow.


3
Я не согласен. «Строго типизированный» означает, что можно определить тип данных значения, и разрешены только операции, соответствующие этому типу. «Динамический» и «статический» адрес, когда это определение может быть сделано.
joel.neely

2
Вы делаете понимают иронию пытается опровергнуть утверждение , что там нет согласованного определения, введя еще одно определение, не так ли?
Jörg W Mittag

1
@Jorg: Не пытаюсь представить еще одну; просто укажите тот, который обычно используется в кругах, по которым я двигаюсь.
joel.neely

1

Существует континуум с множеством параллельных направлений между «слабо типизированным» и «строго типизированным», двумя терминами, которые даже не имеют четкого определения.

C является статически типизированным, поскольку компилятор знает, какой объявлен тип каждой локальной переменной и элемента структуры.

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


0

В чем причина вашего запроса? Причина, по которой я спрашиваю, заключается в том, что это небольшая разница, и ваше конкретное использование «строго типизированного» может потребовать более или менее разъяснений. Я бы определенно сказал, что Java и другие языки имеют более жесткие ограничения на диалог неявных типов.


В основном из любопытства, но я подаю заявку на должность C и хотел знать, если они спросят меня об этом.
Sydius

Тогда, вероятно, более длинный ответ, который дает нюансы того, что «строго типизированный» является лучшим подходом, а не просто «да» или «нет».
BobbyShaftoe

0

Трудно дать конкретный ответ, когда нет конкретного определения термина «строго типизированный». Я бы сказал, что C строго типизирован в том смысле, что каждая переменная и каждое выражение имеет тип, но слабо типизирован, так как он позволяет вам изменять типы с помощью приведения типов и переинтерпретировать представление одного типа как другого.


Есть официальный деф. для строго типизированных. В нем говорится, что файл sys. является ST, когда гарантируется отсутствие ошибки типа времени выполнения. Пример: ML, Haskell. Это полезно для того, чтобы система опускала теги типов внутри объектов и, тем не менее, применяла операторы к правильным типам. Потому что перед выполнением мы знаем, что теги в объектах не нужны. Поскольку C имеет доступ к произвольным
заметкам

0

Я бы сказал, что C настолько строго типизирован, как того требует ваш компилятор / платформа. Например, если вы строите на строгой платформе, разыменование перфорированного указателя типа может сломаться:

void m_free(void **p)
{
        if (*p != NULL) {
                free(*p);
                *p = NULL;
        }
}

....
char *str = strdup("foo");
m_free((void **) &foo);

Теперь, если вы скажете компилятору пропустить строгий псевдоним, это не проблема, но не очень переносимая. В этом смысле расширение границ языка возможно, но, вероятно, не лучшая идея. Это выходит за рамки типичного приведения типов, т. Е. Приведения типов к int до тех пор, пока они не выполняются, и действительно показывает одну из возможных ловушек void.

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



-1

Не строго типизированный.

Подумайте, что следующий прототип функции сообщает вам о типах данных аргументов:

void func (int n, char ch, ...);

Ничего. Поэтому я предлагаю здесь не применять строгую типизацию.


А? Он говорит вам, что есть int, за которым следует char, за которым следует любое количество аргументов любого типа. Это не «ничего».
Лоуренс Дол

... ничего не сообщает вам о типах переданных аргументов. Верно, что известен тип самой функции . Так сказал Software Monkey.
Йоханнес Шауб - лит

Я говорю о «любом количестве аргументов любого типа». Цепь настолько сильна, насколько ее самое слабое звено.
joel.neely

-3

Я бы сказал, что это строго типы, поскольку каждое выражение имеет тип, который не является функцией его значения; ei это может быть известно до времени выполнения.

OTOH Я не уверен, что это правильное описание строго типизированного. Единственное более сильное утверждение, которое я вижу для языка, - это уверенность в том, что вы не можете ниспровергнуть систему типов во время выполнения, переинтерпретируя приведение типов, объединения, вызовы на другие языки, указатели, язык ассемблера и т. Д. Подобные языки существуют, но настолько искалечены, что, кажется, не представляют особого интереса для программистов, за исключением высокоуровневых и академических кругов. Как заметил кто-то, чтобы действительно сделать это правильно, вам нужно иметь такие типы, как nonZeroIntи еще много чего. Фу.


3
Что нет? Мое определение строго типизированного или C?
BCS,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.