Почему оператор разыменования (*) также используется для объявления указателя? - PullRequest
52 голосов
/ 31 декабря 2011

Я не уверен, что это правильный вопрос программирования, но это то, что меня всегда беспокоило, и мне интересно, единственный ли я.

При первоначальном изучении C ++ я понялКонцепция ссылок, но указатели меня смутили.Почему ты спрашиваешь?Из-за того, как вы объявляете указатель.

Обратите внимание на следующее:

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, но при первом изучении C ++ я связал символ * с разыменованием, поэтому я решил, что разыменованный int необходимбыть переданным.Я бы попытался передать *y в foo, что, очевидно, не работает.

Не было бы проще иметь отдельный оператор для объявления указателя?(или для разыменования).Например:

void test(int@ x)
{
}

Ответы [ 6 ]

83 голосов
/ 31 декабря 2011

В Развитие языка C , Деннис Ричи объясняет свои рассуждения так:

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

int i, *pi, **ppi; объявить целое число, указатель на целое число, указатель на указатель на целое число. Синтаксис этих объявлений отражает наблюдение, что i, *pi, and **ppi все дают тип int когда используется в выражении.

Аналогично, int f(), *f(), (*f)(); объявляем функция, возвращающая целое число, функция, возвращающая указатель на целое число, указатель на функцию, возвращающую целое число. int *api[10], (*pai)[10]; объявляет массив указателей на целые числа и указатель на массив целых чисел.

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

Случайность синтаксиса способствовала воспринимаемой сложности язык. Оператор косвенного обращения, записанный * в C, является синтаксически унарный префиксный оператор, как в BCPL и B. Это хорошо работает в простые выражения, но в более сложных случаях круглые скобки требуется направить разбор. Например, чтобы отличить перенаправление через значение, возвращаемое функцией от вызова функция, обозначенная указателем, пишет *fp() and (*pf)() соответственно. Стиль, используемый в выражениях, распространяется на объявления, поэтому имена могут быть объявлены

int *fp(); int (*pf)();

В более изящных, но все же реалистичных случаях, все становится хуже: int *(*pfp)(); - указатель на функцию возврат указателя на целое число.

Происходит два эффекта. Что наиболее важно, C имеет относительно богатый набор способов описания типы (по сравнению, скажем, с Паскалем). Объявления на языках как выразить как C - Алгол 68, например - описать объекты, одинаково трудно понять, просто потому что сами объекты сложны. Второй эффект обязан деталям синтаксиса. Объявления в C должны быть читать в стиле «наизнанку», который многим трудно понять. Сетхи [Сетхи 81] заметил, что многие из вложенных объявления и выражения стали бы проще, если бы косвенность оператор был принят в качестве постфиксного оператора вместо префикса, но к тому времени было уже слишком поздно что-либо менять.

14 голосов
/ 31 декабря 2011

Причина понятнее, если вы напишите это так:

int x, *y;

То есть x и * y являются целыми числами. Таким образом, у является целым *.

10 голосов
/ 31 декабря 2011

Это решение на языке, предшествующее C ++, поскольку C ++ унаследовало его от C. Я однажды услышал, что мотивация состоит в том, что объявление и использование будут эквивалентны, то есть, учитывая объявление int *p; выражение *pимеет тип int так же, как с int i; выражение i имеет тип int.

6 голосов
/ 31 декабря 2011

Поскольку комитет и те, кто разрабатывал C ++ за десятилетия до его стандартизации, решили, что * должен сохранить свои первоначальные три значения :

  • Тип указателя
  • Оператор разыменования
  • Умножение

Вы правы, предполагая, что множественные значения * (и, аналогично, &) сбивают с толку.В течение нескольких лет я придерживался мнения, что они являются серьезным препятствием для понимания новичками в языке.


Почему бы не выбрать другой символ для C ++?

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


Почему бы и нетвыбрать другой символ для C?

Это невозможно знать наверняка, но есть несколько аргументов, которые могут быть и были сделаны.Прежде всего, идея, что:

, когда идентификатор [an] появляется в выражении той же формы, что и декларатор, он дает объект указанного типа.{K & R, p216}

Это также, почему программисты на C стремятся [цитата нужна] предпочитают выравнивать свои звездочки справа, а не слева, то есть:

int *ptr1; // roughly C-style
int* ptr2; // roughly C++-style

хотя оба варианта встречаются в программах на обоих языках, по-разному.

5 голосов
/ 31 декабря 2011

Страница 65 из Эксперт C Программирование: Deep C Secrets включает в себя следующее: А затем существует философия C, согласно которой объявление объекта должно выглядеть как его использование.

Страница 216 из Язык программирования C, 2-е издание (он же K & R) включает в себя: Декларатор читается как утверждение, которое, когда его идентификатор появляется в выражении той же формы, что иобъявитель, он возвращает объект указанного типа.

Я предпочитаю способ, которым Ван дер Линден выражает его.

3 голосов
/ 09 апреля 2015

Хаха, я чувствую твою боль, у меня точно такая же проблема.

Я думал, что указатель должен быть объявлен как &int, потому что имеет смысл, что указатель является адресом чего-то.

Через некоторое время я подумал, что каждый тип в C должен читаться в обратном направлении , как

int * const a

для меня

a constant something, when dereferenced equals an int. То, что должно быть разыменовано , должно быть указателем.

...