ИМХО "самая сломанная" часть системы типов C состоит в том, что понятия
- значения / параметры, которые являются необязательными
- изменяемые значения / передача по ссылке
- Массивы
- параметры функции без POD
все сопоставлены с единственной языковой концепцией «указатель». Это означает, что если вы получите параметр функции типа X*
, это может быть необязательный параметр, можно ожидать, что функция изменит значение, на которое указывает X*
, возможно, существует несколько экземпляров X
после того, как указано (сколько открыто - число может быть передано в качестве отдельного параметра, или какое-то специальное значение «терминатора» может пометить конец массива, как в строках с нулевым символом в конце). Или параметр может быть просто одной структурой, которую вы не ожидаете изменить, но дешевле передавать ее по ссылке.
Если вы получите что-то типа X**
, это может быть массив необязательных значений или массив простых значений, и вы должны его изменить. Или это может быть двумерный зубчатый массив. Или необязательное значение, переданное по ссылке.
Напротив, возьмем семейство языков ML (F #, OCaML, SML). Здесь эти понятия отображаются в отдельные языковые конструкции:
- необязательные значения имеют тип
X option
- значения, которые изменяются / передаются по ссылке, имеют тип
X ref
- массивы имеют тип
X array
- и не-POD типы могут передаваться как POD. Поскольку они не являются изменяемыми, компилятор может передавать их по ссылке внутри, но вам не нужно знать об этой детали реализации
И вы, конечно, можете объединить их, то есть int optional ref
- это изменяемое значение, которое может быть установлено равным нулю или некоторому целочисленному значению. int ref optional
, с другой стороны, является необязательным изменяемым значением; это может быть ничто (и никто не может изменить его), или это может быть какой-то изменяемый int (и вы можете изменить его на любой другой изменяемый, но не ни к чему).
Эти различия очень тонкие, , но вы должны сделать их независимо от того, программируете ли вы на ML или нет . В C вы должны делать те же различия, но они явно не указаны в системе типов. Вы должны очень внимательно прочитать документацию, или вы можете ввести незначительные (читай: трудно найти) ошибки, если вы неправильно понимаете, какой вид использования указателя подразумевается, когда.