Почему считается, что 'T *name' - это путь C, а 'T *name' - как путь C++?
Примечание: этот вопрос о позиции звездочки (*
).
В большинстве кода C, который я вижу (например, в руководстве по сетевому программированию Beej), все объявления / определения переменных используют T *name
формат, то есть, связать *
к имени переменной. Указатель считается принадлежащим переменной, а не типу.
В большинстве кода C++, который я вижу, формат T* name
то есть связывает *
к типу переменной. Указатель считается принадлежащим типу, а не переменной. Я сам, как чистый C++ кодер, также использую этот формат, так как указатель на тип явно (для меня) относится к типу, а не к переменной. (Кстати, даже стандарт C++ использует этот формат в примерах.:))
Есть ли (историческая) причина для этого? Изменился ли образ мышления, когда программисты начали заниматься C++?
Было бы также хорошо, если бы C-кодер (который использует первый формат) мог объяснить, почему он / она использует его, а не последний.
10 ответов
Из часто задаваемых вопросов о стиле и методике Страуструпа.
"Типичный программист C" пишет
int *p;
и объясняет это*p
это то, чтоint
"подчеркивая синтаксис, и может указывать на грамматику объявления C (и C++), чтобы аргументировать правильность стиля. Действительно,*
привязывается к имениp
в грамматике."Типичный программист C++" пишет
int* p;
и объясняет этоp
это указатель наint
"подчеркивающий тип. Действительно типp
являетсяint*
, Я явно предпочитаю этот акцент и считаю его важным для хорошего использования более продвинутых частей C++.
Если бы я рискнул предположить, я бы сказал, что это потому, что люди на C++ с большей вероятностью считают информацию о типах чем-то самоцелью, потому что шаблоны позволяют программно манипулировать типами во время компиляции. Они также гораздо реже объявляют несколько переменных в одном объявлении.
T*
Стиль сосредотачивает информацию о типе в одном месте и выделяет ее, а также путаницу, которая может возникнуть из-за чего-то вроде T* foo, bar;
с этим синтаксисом не проблема, если вы никогда не объявляете две переменные в одном выражении.
Лично я нахожу T*
стиль, чтобы быть действительно неприятным и не любить его безмерно. *
это часть информации о типе, это правда, но то, как компилятор разбирает его, делает его фактически привязанным к имени, а не к типу. я думаю T*
путь скрывает что-то важное, что происходит.
В моих наблюдениях кажется, что я редкость в сообществе C++. Я заметил то же самое, что и у вас, о том, какой стиль наиболее популярен.
Чтобы было ясно, конечно, любой стиль работает на любом языке. Но я замечаю то же самое, что и вы, что один стиль имеет тенденцию быть немного более распространенным в C-коде, а другой - немного более распространенным в C++.
Лично я не согласился бы с этим - я не думаю, что есть способ C или C++ сделать это. Я никогда не видел никаких доказательств, чтобы это предположить. Тем не менее, у меня есть гипотеза о том, почему синтаксис со звездочкой ближе к объявленному имени переменной в C.
В C (по крайней мере, в C89, подавляющем большинстве C), вы должны объявить все свои переменные в верхней части блока. Это приводит к тому, что программисты делают
T a, b, c;
относительно часто, в то время как в C++ это редко. (В C++ вы объявляете переменные рядом с тем местом, где они используются, а переменные часто имеют параметры конструктора и т. Д.; поэтому редко объявлять несколько объектов в одной строке)
Это также, случается, единственный случай, когда синтаксис имеет значение, потому что утверждение
T* a, b, c;
объявляет один указатель, а не три, которые может ожидать программист.
Поскольку размещение более чем одной декларации в одной строке более распространено в C, а также является единственным случаем, когда положение звездочки имеет значение, программист с большей вероятностью связывает звездочку с переменной.
Тем не менее, я никогда не видел никаких доказательств этого - это всего лишь догадка.
Несколько человек упомянули очень хорошие моменты. Я просто хочу отметить, что, хотя C очень сильно сохранил значение "объявление отражает использование", C++ этого не сделал. Несколько объявлений в C++ не отражают использование в объявлениях;
int &ref; // but "&ref" has type "int*", not "int".
int &&ref; // but "&&ref" is not valid at all.
Я не думаю, что программисты на C++, пишущие по-другому, на самом деле имеют такую причину, но это может быть чем-то, что мешает авторам книг C++ упомянуть об этом, что может повлиять на программистов на C++.
Причина, по которой программисты на C склонны использовать один стиль, в то время как программисты на C++ используют другой стиль, довольно проста: Kernighan & Ritchie использовали "стиль C" в своей книге, в то время как Страуструп использовал "стиль C++" в своей книге.
В K&R они используют type *name
нотация, так что, может быть, это то, где многие программисты C получили это.
Потому что Бьярне имел преимущество в ретроспективе: он понял, что синтаксис объявления C был "экспериментом, который не удался" (читай: синтаксис объявления C запаздывает). На остальные уже ответили другие.
Просто, чтобы бросить спор в этот вопрос:
- Пользователи C++ обычно заявляют, что одно объявление на строку позволяет поставить звездочку на тип (слева).
int* a; int* b;
- И C, и C++ анализируются со звездочкой, прикрепленной к имени (справа).
int *a;
- Препроцессоры C++ часто перемещают звездочку влево. С препроцессорами передвиньте его вправо.
- В любом языке, размещение его слева будет выглядеть странно для объявления нескольких переменных одного типа в одном выражении.
int* a, * b, * c;
- Есть некоторые синтаксические элементы, которые выглядят глупо с левой стороны.
int* (* func)()
,
Есть другие элементы C, которые используются неправильно, такие как const
, который принадлежит справа тоже! int const a;
, Обычно это ставится слева от типа, несмотря на принадлежность к типу слева от него. Многие компиляторы должны быть изменены для обработки этого использования. В C++ вы можете наблюдать, что это согласуется с константными методами, так как компилятор не может вывести вас, если он помещен слева: int A::a() const
, Это также ломает с вложенным использованием const
, restricted
и дружит с такими декларациями как int const *
, Обычное использование const
предположил бы, что это постоянный указатель на целое число, но это на самом деле int *const
,
ТЛ; др
Вы все делали все это неправильно, все расставляли правильно.
Объявления C следуют тем же правилам (например, приоритет), что и выражения. На самом деле, совершенно правильно рассматривать декларацию как
int *foo;
как объявление типа выражения *foo
(т.е. оператор косвенности применяется к foo
) как int
вместо foo
как тип int*
,
Однако, как уже указывалось ранее, в C++ принято думать о типах как об отдельном и - из-за шаблонов - изменяемой сущности, и поэтому имеет смысл использовать объявление вроде
int* foo;