2010-03-11 3 views
31

Я понимаю, что вы можете просто #define некоторые целые числа, но почему C не имел выделенного булева типа данных до C99?Почему C не имел тип булевых данных до C99?

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

+5

-1: Какая проблема решается, зная историю реализации Kernighan's и Ritchie's деталей C? –

+38

@ S.Lott - извините, я пропустил понимание цели StackOverflow? Этот вопрос не связан с программированием? Из FAQ: «Это место для вопросов, на которые можно ответить». «Пока ваш вопрос ... подробный и конкретный, написанный ясно и просто, интерес к хотя бы одному другому программисту». Что еще я пропустил? –

+19

@ S.Lott Я подозреваю, что вы должны удалить главу «Фон и история» из своей книги Python. –

ответ

24

Если вы проводите немного времени в библиотеке, вам не нужно спекулировать. Вот некоторые утверждения, взятые из Dennis Ritchie's paper on the evolution of C. Контекст состоит в том, что Деннис строит на языке Кена Томпсона B, который был реализован на очень маленькой PDP-7, машине, адресованной словом. Из-за растущего интереса группа получила один из первых PDP-11. Деннис пишет:

Появление PDP-11 выявило несколько несоответствий семантической модели B. Во-первых, его механизмы обработки символов, унаследованные с небольшими изменениями от BCPL, были неуклюжими: использование библиотечных процедур для распространения упакованных строк в отдельные ячейки, а затем для переупаковки или для доступа к отдельным символам, а также для замены отдельных символов стало чувствовать себя неудобно, даже глупо, на байт-ориентированная машина.

Модель B и BCPL подразумевала накладные расходы при работе с указателями: языковые правила, определяя указатель как индекс в массиве слов, принудительные указатели должны быть представлены как индексы слов. Каждая ссылка указателя генерировала преобразование шкалы времени выполнения из указателя в адрес байта, ожидаемый аппаратным обеспечением.

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

(выделено мной.)

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

1

Потому что они не ввели его. Извините, если это звучит сногсшибательно, но в основном это не было определено как таковое.

Помните, что большинство людей #define TRUE и FALSE.

Вы можете сказать, что стандарт bool IS - но, очевидно, он не был стандартным до C99 - который был сделан 10 лет назад;) Они добавили его тогда, когда стало очевидным недостающий элемент.

+3

вы просто перефразировали его: P –

+5

+1: «Потому что они не ввели его». Единственный возможный ответ. –

+0

Это стандарт не только в программировании, но и в процессе мышления при решении проблемы. – xyz

0

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

17

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

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

+11

Помните, что ранний C также использовал 'char *' до 'void *', который был стандартизован как общий тип указателя. Процессор не имел понятия «void», поэтому на нем использовался указатель данных наименьшего разрешения, который понял аппарат. Более поздние «абстрактные» понятия типа «void *». C - очень близкий к металлу язык и абстрагирование true/false в новый тип данных, который не отражает того, что аппаратное средство может однозначно понять, не имеет большого смысла ('bool' просто будет' char' с дополнительными ограничениями, достаточно простыми, чтобы 'typedef' сам, если вам это действительно нужно). – bta

7

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

+1

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

9

ЦПУ не имеет «логического типа», он работает только с байтами и кратным им, поэтому булевский тип не имел смысла в то время, поскольку он не давал преимущества (зачем использовать тип, когда вы можете только проверить «0» или «не является нулевым»)

+2

Уверен, что у процессора есть булевы типы. Регистр флагов наполнен ими! – xtofl

+1

Да, но они не универсальны. – dbemerlin

10

Общепринято (и все еще в некоторых случаях) обрабатывать ноль как ложное и любое ненулевое значение как истину. Это имеет преимущества для сокращения: например, вместо while (remaining != 0) вы можете просто использовать while (remaining).

Некоторые языки, стандартизированные по истине, являются -1. Причиной этого является то, что в двухкомпонентной нотации (которую большинство компьютеров используют для представления отрицательных чисел), побитовое, а не 0, равно -1 (в 8-битовом двоичном формате 11111111 является десятичным -1).

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

+0

+1 за самый подробный ответ –

+2

Я всегда находил 0/-1 вещь интересной, когда я ее впервые обнаружил - тем более, что многие преподаватели/преподаватели неправильно объяснили, что положительный 1 был «истинным». –

+4

Положительный 1 ** является ** «истинным» в C, в том смысле, что операторы сравнения и логические и/или/не-операторы оценивают 1 или 0 для истинных или ложных, соответственно. Но лучше не думать об истинности как о ценности, поскольку любое ненулевое значение истинно. –

5

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

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

Реальным вопросом является то, почему в C99 был добавлен булев тип.Я предполагаю, что речь идет о нескольких факторах. Во-первых, они поняли, что удобство для программиста теперь, как правило, более важно, что дает абсолютную максимальную производительность. Во-вторых, компиляторы теперь делают немного более глобальный анализ, поэтому, по крайней мере, можно предположить, что кто-то может написать компилятор, который пытается выбрать представление, наиболее подходящее для конкретной программы (хотя я не знаю, что действительно делает).

+0

+1: Мне понравилось упоминание пространства-времени-компромисс. Это очень важный момент. – Arun

+0

В некоторых компиляторах 'int' является самым быстрым форматом для хранения логического значения. Однако на многих (но не на всех) «char» будет так же быстро. Некоторые процессоры с встроенной системой имеют особый тип «бит», который еще быстрее (хотя такие процессоры обычно не позволяют включать типы «бит» в другие структуры). Было бы глупо хранить логическое значение в 'int' на платформе, где' char' будет так же быстро (или, для некоторых встроенных процессоров, даже быстрее). – supercat

+0

. Что суперкарт также сказал, что первоначальная цель для c была, как правило, машинами с ограниченной памятью, вы почти всегда предпочитали бы управлять своей бит-упаковкой вручную. Тогда добавление булевского типа поощрило бы то, что тогда считалось бы ужасным выходом машинного кода. –

4

Исторические причины, вероятно:

CPL, который находился под сильным влиянием Алголом, скорее всего, имел логический тип, но мой Google-фу не достаточно, чтобы найти ссылку для этого. Но CPL был слишком амбициозен для своего времени, в результате чего была урезана версия под названием BCPL, которая имела то преимущество, которое вы могли бы реально реализовать на доступном оборудовании.

BCPL был только один типа - «слова» - которое было истолковано как ложь в логических контекстах, если 0 и истинный, если ~0 (то есть дополнение 0, который будет представлять значение -1, если интерпретировать как подписанное twos- целочисленное число). Интерпретация любого другого значения зависела от реализации.

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

5

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

  • бит адресации процессоров были не совсем распространены (и до сих пор нет), так что компилятор не будет действительно иметь возможность использовать «истинное логическое значение» типа, чтобы сохранить любое пространство - логическое значение по-прежнему будет как минимум равным char (если вы надеетесь получить доступ к нему эффективно).

  • Типы более узкие, чем int расширяются до int в выражениях во всяком случае - так логические операторы будут по-прежнему работать на int операндов.

..но похоже, что не было достаточно убедительного случая, чтобы выделенный булев тип фактически передавал практические выгоды.

Помните, что язык C действительно есть множество операторов, которые производят логические результаты (определяется либо 0 или 1) - !, &&, ||, !=, ==, <, <=, > и >= - так это только выделенный булев тип, которого нет.

1

Добавление отдельного типа «Boolean», не совместимого с целыми числами, сделало бы компилятор более сложным, чем просто использование целых чисел для этой цели. Наличие отдельного булева типа, совместимого с целыми числами, требует указания возможных последствий сохранения значения, отличного от 0 , или 1 в логическом объекте, или выполнения числовых вычислений на объекте Boolean , представление которого не содержит ни ассоциированного битового шаблона с «0» или «1». Дано:

someBool = intFunction(); 
someInt = someBool; 

требуя, чтобы someInt должен получить значение 1, если intFunction возвращает любое ненулевое значение, как правило, делает выше дороже

someChar = intFunction(); 
someInt = someChar; 

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

someChar = !!intFunction(); 
someInt = someChar; 

Поскольку все, что может быть сделано с помощью логических типов также может быть сделано без них, и во многих случаях гр ode, который использует типы символов, может быть более эффективным, чем булевы типы, я бы предположил, что никогда не было (и до сих пор нет) никакой реальной необходимости для них.