Почему оператор разыменования (*) также используется для объявления указателя?
Я не уверен, что это правильный вопрос программирования, но это то, что меня всегда беспокоило, и мне интересно, не единственный ли я.
Когда я изучал С++, я понял концепцию ссылок, но указатели меня смутили. Почему ты спрашиваешь? Из-за того, как вы объявляете указатель.
Рассмотрим следующее:
void foo(int* bar)
{
}
int main()
{
int x = 5;
int* y = NULL;
y = &x;
*y = 15;
foo(y);
}
Функция foo(int*)
принимает в качестве параметра указатель int
. Поскольку я объявил y
как int
указатель, я могу передать y
в foo
, но когда сначала изучил С++, я связал символ *
с разыменованием, поэтому я решил разыменовать int
необходимый для передачи. Я попытался бы передать *y
в foo
, который, очевидно, не работает.
Не было бы проще иметь отдельный оператор для объявления указателя? (или для разыменования). Например:
void test([email protected] x)
{
}
Ответы
Ответ 1
В Развитие языка C Деннис Ричи объясняет свои рассуждения таким образом:
Второе нововведение, которое наиболее четко отличает C от его предшественники - это более полная структура типа и особенно ее выражение в синтаксисе объявлений... с учетом объекта любого типа, должно быть возможно описать новый объект, который собирает несколько в массив, выдает его из функции или указатель на это... [Это] привело к синтаксис объявления для имен, дублирующих синтаксис выражения в котором обычно появляются имена. Таким образом,
int i, *pi, **ppi;
объявить целое число, указатель на целое число, a указатель на указатель на целое число. Синтаксис этих объявлений отражает, что i, *pi, and **ppi
все дают тип int
при использовании в выражении.
Аналогично, int f(), *f(), (*f)();
declare функция, возвращающая целое число, функция, возвращающая указатель на integer, указатель на функцию, возвращающую целое число. int *api[10],
(*pai)[10];
объявить массив указателей на целые числа и указатель на массив целых чисел.
Во всех этих случаях декларация переменная напоминает ее использование в выражении, тип которого является одним названный во главе декларации.
Авария синтаксиса способствовала воспринимаемой сложности язык. Оператор косвенности, записанный * в C, синтаксически унарный префиксный оператор, как и в BCPL и B. Это хорошо работает в простые выражения, но в более сложных случаях круглые скобки требуется для направления анализа. Например, чтобы различать косвенность через значение, возвращаемое функцией от вызова функция, обозначенная указателем, записывает *fp() and (*pf)()
соответственно. Стиль, используемый в выражениях, объявления, поэтому имена могут быть объявлены
int *fp(); int (*pf)();
В более богатых, но все же реалистичных случаях, все становится хуже: int *(*pfp)();
- указатель на функцию возвращая указатель на целое число.
Возникают два эффекта. Самое главное, C имеет относительно богатый набор способов описания (сравнивается, скажем, с Паскалем). Объявления на языках как например, C-Algol 68, например, описывают объекты одинаково трудно понимаете, просто потому, что сами объекты сложны. второй эффект связан с деталями синтаксиса. Декларации на C должны быть читать в стиле "наизнанку", который многим трудно понять. Sethi [Sethi 81] заметил, что многие из вложенных декларации и выражения станут проще, если косвенность оператор был принят как постфиксный оператор вместо префикса, но к тому времени было уже слишком поздно меняться.
Ответ 2
Причина яснее, если вы пишете это следующим образом:
int x, *y;
То есть, и x, и y являются int. Таким образом, y является int *.
Ответ 3
Это решение языка, которое предшествует С++, поскольку С++ унаследовал его от C. Я когда-то слышал, что мотивация заключалась в том, что объявление и использование были бы эквивалентны, то есть с учетом объявления int *p;
выражение *p
имеет тип int
таким же образом, что при int i;
выражение i
имеет тип int
.
Ответ 4
Поскольку комитет и те, кто разработал С++ за десятилетия до его стандартизации, решили, что *
должен сохранить свои исходные три значения:
- Тип указателя
- Оператор разыменования
- Умножение
Вы правы, чтобы предположить, что множественные значения *
(и, аналогично, &
) запутывают. В течение нескольких лет я придерживался мнения, что это значительный барьер для понимания новичков языка.
Почему бы не выбрать другой символ для С++?
Обратная совместимость является основной причиной... лучше всего использовать существующие символы в новом контексте, чем разрывать программы C, переведя ранее не-операторы в новые значения.
Почему бы не выбрать другой символ для C?
Невозможно знать наверняка, но есть несколько аргументов, которые могут быть — и были? сделал. Прежде всего, идея состоит в том, что:
когда идентификатор [an] появляется в выражении той же формы, что и декларатор, он дает объект указанного типа. {K & R, p216}
Вот почему программисты C стремятся [править] предпочитают выравнивать свои звездочки вправо, а не влево, то есть:
int *ptr1; // roughly C-style
int* ptr2; // roughly C++-style
хотя обе разновидности встречаются в программах обоих языков, изменяясь.
Ответ 5
Страница 65 из Экспертное программирование C: Deep C Secrets включает следующее: И тогда существует философия C, что объявление объекта должно выглядеть как его использование.
Страница 216 of Язык программирования C, второе издание (ака K & R) включает в себя: декларатор читается как утверждение о том, что когда его идентификатор появляется в выражении той же формы, что и декларатор, он дает объект указанного типа.
Я предпочитаю, как это делает ван дер Линден.
Ответ 6
Ха-ха, я чувствую твою боль, у меня была такая же проблема.
Я думал, что указатель должен быть объявлен как &int
, потому что имеет смысл, что указатель является адресом чего-то.
Через некоторое время я подумал о себе, каждый тип в C должен быть прочитан назад, например
int * const a
для меня
a constant something, when dereferenced equals an int
.
То, что должно быть разыменовано, должно быть указателем.