Строго типизированные указатели в C (гипотетически) - PullRequest
10 голосов
/ 26 марта 2011

Вот вопрос, который я получил сегодня на экзамене:

В C предположим, что указатели строго типизированы (т. Е. Указатель на int не может быть использован для указания на символ). Это уменьшает его выразительную силу? Если нет, почему и как бы вы компенсировали это ограничение? Если да, то как? А какие еще конструкции вы бы добавили, чтобы «выровнять» потерю выразительной силы C?

Некоторые дополнительные детали:

  • Снижая выразительность, я думаю, это означает следующее: вы не сможете создавать определенные программы, которые могли бы раньше.
  • Строго набранные указатели означают, что вы не можете делать что-то вроде: int x = 5; int *p = &x; char *temp = (char*)p;
  • Сюда входит (void*) конверсий

Я включил и мой ответ ниже.

Ответы [ 8 ]

5 голосов
/ 26 марта 2011

Означает ли это также не больше void*? Если это так, то да: выразительность C будет ограничена, поскольку malloc будет невозможно реализовать. Вам нужно было бы добавить новый типизированный механизм бесплатного распределения хранилища в духе C ++ new.

(Или нет: C все еще будет завершен по Тьюрингу. Но я не думаю, что это означает здесь). На самом деле, C даже не завершен по Тьюрингу; см. комментарии ниже.

2 голосов
/ 26 марта 2011

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

Если вы убрали требование, чтобы указатели были представлены как char [sizeof (pointer type)], то формальноуказанный язык может в принципе иметь дело с бесконечным количеством данных, и он будет полон по Тьюрингу.

1 голос
/ 26 марта 2011

Я не думаю, что это снижает его выразительность - вы все еще можете написать машинный интерпретатор Тьюринга, то есть он завершен.См., Например, этот код гольф-нити .

Если вы имеете в виду выразительную мощность с точки зрения удобства пользователя, то это определенно сильно ограничивает C, поскольку механизм выделения памяти (malloc & co.) Будетдолжны быть изменены.

1 голос
/ 26 марта 2011

Этот вопрос похож на вопрос о том, какие полезные / допустимые варианты использования приведения указателей.Вот некоторые из них:

Без приведения указателей у вас должно быть несколько версий memcpy, memmove, malloc, поскольку все они требуют реализации и использования преобразований указателей.В случае malloc выделение памяти для пользовательских struct s становится невозможным.

В немного другой категории вы не можете реализовать полиморфный qsort (тот, который предоставляется стандартными библиотеками, сортируетмассив void* и может эффективно использоваться для сортировки массивов различных типов указателей.

Что касается того, какой тип функции позволит восстановить выразительную силу, система типов, которая распознает полиморфизм, так что вы делаетене нужно кодировать его с небезопасным приведением указателей, было бы отличным шагом. Языки семейства ML уже давно используют такую ​​систему типов, и если вы знакомы с обобщениями Java , они придерживаются той же линии мышления.

1 голос
/ 26 марта 2011

Ну, это очень субъективный вопрос. Соедините это с тем фактом, что я понятия не имею, что такое «выразительная сила»;)

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

Как бы вы обошли эти ограничения? Возможно, реализовать функцию «cast» или просто шаблонную функцию memcpy, которая может переосмыслить память, было бы огромным бонусом для оптимизации и, для людей, подобных мне, производительности. Это может быть даже план, предусматривающий включение некоторого рода «id» класса в поток байтов, чтобы вы знали, что он может быть интерпретирован как определенный класс.

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

0 голосов
/ 26 марта 2011

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

union alltypepointers  
{  
    char* c,  
    short* s,
    int* i,  
    float* f,
    double* d,
    ...
};  

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

int variable = 0x2345;
alltypepointers p;
p.i = &variable;
char *temp = p.c;
p.c++;
int newint=*p.i;

Таким образом, вы все равно можете делать все, что могли сделать раньше => нет уменьшения выразительной силы.

0 голосов
/ 26 марта 2011

В C, предположим, что указатели строго типизированы (т. Е. Указатель на int не может использоваться для указания на символ).

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

0 голосов
/ 26 марта 2011
(someType *)((void *)somePtr)

это конструирование позволяет вам конвертировать любой указатель в (someType *).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...