Почему звездочка перед именем переменной, а не после типа? - PullRequest
163 голосов
/ 29 декабря 2008

Почему большинство программистов на C называют переменные следующим образом:

int *myVariable;

а не так:

int* myVariable;

Оба действительны. Мне кажется, что звездочка является частью типа, а не частью имени переменной. Кто-нибудь может объяснить эту логику?

Ответы [ 12 ]

1 голос
/ 01 августа 2015

Я уже ответил на аналогичный вопрос в CP, и, поскольку никто не упомянул об этом, также здесь я должен указать, что C - это язык свободного формата , независимо от стиля, который вы выберете, он будет в порядке, пока синтаксический анализатор может сделать различие каждого жетона. Эта особенность C приводит к особому типу состязаний под названием C obfuscation Competition .

0 голосов
/ 04 июня 2019

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


Спецификаторы типа забытого указателя

Формально «звезда» не принадлежит ни типу, ни имени переменной, она является частью своего собственного грамматического элемента с именем указатель . Формальный синтаксис C (ISO 9899: 2018):

(6.7) объявление:
спецификаторы объявлений список инициаторов объявлений opt ;

Где спецификаторы объявлений содержит тип (и хранилище), а список инициаторов объявлений содержит указатель и имя переменной. Что мы увидим, если разберем синтаксис этого списка объявлений далее:

(6.7.6) декларатор:
указатель опция прямое объявление
...
(6.7.6) указатель:
* список квалификаторов типов opt
* список квалификаторов типов opt указатель

Если декларатор - это полное объявление, прямой декларатор - это идентификатор (имя переменной), а указатель - это звезда, за которой следует необязательный список квалификаторов типов, принадлежащий самому указателю.

То, что делает различные аргументы стиля о том, что «звезда принадлежит переменной» несовместимо, заключается в том, что они забыли об этих квалификаторах типа указателя. int* const x, int *const x или int*const x?

Рассмотрим int *const a, b;, какие типы a и b? Не так очевидно, что «звезда принадлежит переменной» больше. Скорее, можно было бы задуматься о том, где находится const.

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

Список квалификаторов типов для указателя может вызвать проблемы у тех, кто использует стиль int *a. Те, кто использует указатели внутри typedef (что мы не должны, очень плохая практика!) И думают, что «звезда принадлежит имени переменной», как правило, пишут эту очень тонкую ошибку:

    /*** bad code, don't do this ***/
    typedef int *bad_idea_t; 
    ...
    void func (const bad_idea_t *foo);

Это компилируется чисто. Теперь вы можете подумать, что код сделан правильно. Не так! Этот код случайно является фальшивой константностью.

Тип foo на самом деле int*const* - самый внешний указатель был сделан только для чтения, а не наведен на данные. Так что внутри этой функции мы можем сделать **foo = n;, и она изменит значение переменной в вызывающей программе.

Это потому, что в выражении const bad_idea_t *foo, * здесь не принадлежит имени переменной! В псевдокоде это объявление параметра следует читать как const (bad_idea_t *) foo и , а не как (const bad_idea_t) *foo. В этом случае звезда относится к скрытому типу указателя - тип является указателем, а указатель с константой записывается как *const.

Но тогда корень проблемы в вышеприведенном примере - это практика скрытия указателей за typedef, а не за * стилем.


Относительно объявления нескольких переменных в одной строке

Объявление нескольких переменных в одной строке широко признано плохой практикой 1) . CERT-C подытоживает это как:

DCL04-C. Не объявляйте более одной переменной на объявление

Просто читая по-английски, здравый смысл соглашается с тем, что декларация должна быть одна декларация.

И не имеет значения, являются ли переменные указателями или нет. Объявление каждой переменной в одной строке делает код более понятным почти в каждом случае.

Таким образом, аргумент о том, что программист запутался из-за int* a, b, плох. Корень проблемы - использование нескольких деклараторов, а не размещение *. Независимо от стиля, вы должны написать это вместо:

    int* a; // or int *a
    int b;

Другим обоснованным, но субъективным аргументом было бы то, что для int* a тип a не вызывает вопросов int*, поэтому звезда относится к определителю типа.

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


1) CERT-C DCL04-C .

...