Можно ли добавить вывод типа на язык C?
Скажем, мы создаем повторную реализацию C, с той лишь разницей, что
эти типы выводятся. Классы хранения и модификаторы все равно должны быть
(const, static, ограничение и т.д.), и ограничиваем наше внимание одиночным
файл C на данный момент. Это можно сделать? Каковы основные
препятствия?
Некоторые мысли о том, что может вызвать проблемы с типом вывода
- структуры с тем же именем поля должны быть устранены вручную.
- тот же для союзов с одинаковыми именами полей
-
возможно, потребуется "из" аннотации, что-то вроде
var i = (uint32_t -> uint64_t) *some_pointer;
Эти проблемы потребуют немного аннотации пользователя, но не должны быть слишком
обременительно, есть ли какая-то проблема с убийцей, которая выводит эту идею из воды?
Изменить: Чтобы уточнить, я не говорю о добавлении дженериков или параметрического полиморфизма, просто введите вывод для существующих типов C.
Изменить 2014: Любой, кто интересуется этой концепцией, может захотеть заглянуть в Rust
Ответы
Ответ 1
C автоматически создает некоторые типы, что усложняет ситуацию. Но для того, чтобы быть работоспособным, вам нужно иметь пару дополнительных отличий от C, поскольку он существует: прямо сейчас стандарт по-прежнему поддерживает до некоторой степени устаревшие программы K & R C и требует, чтобы неуказанные типы обрабатывались определенными способами. (См., Например, правила для параметров функции в отсутствие прототипов. Также было возможно указать функции и переменные без типа, и по умолчанию они будут (int)
. (Как для переменных? Только класс хранения. static foo;
)) Вся эта обработка устаревшего типа должна быть удалена до того, как будет добавлен новый механизм подразумеваемых типов.
Ответ 2
GCC 5.1 поддерживает:
-
__auto_type
расширение, аналогичное С++ 11 auto
-
typeof
расширение, аналогичное С++ 11 decltype
.
-
_Generic
Ключевое слово C11
Пример:
__auto_type i = 1;
assert(_Generic((i), int: 1, default: 0));
Ответ 3
Вывод типов полиморфных функций потребует значительных расширений для системы типа C. Пример
length(p) {
if (p == NULL) return 0;
else return 1 + length(p->next);
}
Этот код должен работать с любым указателем на структуру (или объединение) с полем next
. Вы можете проверить полиморфизм строк, но, по крайней мере, ваша новая система типов должна быть гораздо более выразительной, чем система типа C.
Другой проблемой является перегрузка +
. Какому типу он по умолчанию? Вы хотите, чтобы он перегружался любым числовым типом, например Haskell или С++? Если это так, более большие расширения для системы типов.
Чем больше урок , тем ниже. Достоинства C (как языка, помимо многих прекрасных API, доступных на C),
- У вас есть полный контроль над представлением ваших данных.
- Любое лицо, проверяющее исходный код, может легко прогнозировать затраты времени и пространства.
Эта повестка дня несовместима с полиморфизмом, и полиморфизм является основным преимуществом вывода типа. Если тип вывода является тем, что вы хотите, выберите один из многих прекрасных языков (F #, Haskell, ML), которые поддерживают его изначально.
Ответ 4
В C. можно сделать вывод о типе. Посмотрите на этот инструмент: http://cuda.dcc.ufmg.br/psyche-c. Вы можете набрать часть программы там, и она восстановит декларации отсутствующих типов. Например, если мы будем кормить его вариацией программы Нормана:
int length(T p) {
if (p == NULL) return 0;
else return 1 + length(p->next);
}
Затем psyche-c находит эти объявления:
#include <stdint.h>
#define NULL ((void*)0)
typedef int bool;
bool false = 0;
bool true = 1;
typedef struct T {struct T* next;}* T;
Такая реконструкция типа полезна, например, для завершения кода.
Ответ 5
C имеет сложный набор правил, касающихся поощрения и преобразования типов, которые люди считают запутанными, даже когда они действительно могут видеть типы, с которыми они имеют дело. Я подозреваю, что даже если C имеет тип вывода, было бы необходимо объявить типы, чтобы предотвратить нелепые ошибки каждую третью функцию.
Ответ 6
Некоторые ситуации, когда, я думаю, предполагаемые типы не могут быть использованы:
- указатели нуждаются в определенном типе
- массивы нуждаются в определенном типе
- Параметры функции нуждаются в типе
Я думаю, что это может работать для нескольких случаев, в основном простых локальных переменных.
Даже то, что просто, как вычисление контрольной суммы, требует определенного типа
crc8 = 0x00; /* 8 bits; cf uint8_t crc8 = 0; */
crc32 = 0x00000000; /* 32 bits; cf uint32_t crc32 = 0; */
Это можно сделать для ограниченного использования.