Подтвердить что ты не робот

Можно ли добавить вывод типа на язык C?

Скажем, мы создаем повторную реализацию C, с той лишь разницей, что эти типы выводятся. Классы хранения и модификаторы все равно должны быть (const, static, ограничение и т.д.), и ограничиваем наше внимание одиночным файл C на данный момент. Это можно сделать? Каковы основные препятствия?

Некоторые мысли о том, что может вызвать проблемы с типом вывода

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

    var i = (uint32_t -> uint64_t) *some_pointer;
    

Эти проблемы потребуют немного аннотации пользователя, но не должны быть слишком обременительно, есть ли какая-то проблема с убийцей, которая выводит эту идею из воды?

Изменить: Чтобы уточнить, я не говорю о добавлении дженериков или параметрического полиморфизма, просто введите вывод для существующих типов C.

Изменить 2014: Любой, кто интересуется этой концепцией, может захотеть заглянуть в Rust

4b9b3361

Ответ 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; */

Это можно сделать для ограниченного использования.