Синтаксис указателя в C: почему делает *, только относятся к первой переменной?

Следующее объявление в C:

int* a, b;

объявит a как тип int* и b как тип int. Я хорошо знаю об этом прерывании, но что я хочу знать, то, почему оно прокладывает себе путь. Почему это также не объявляет b как int*, поскольку большинство людей интуитивно ожидало бы? Другими словами, почему делает * обратиться к имени переменной, а не типу?

Уверенный Вы могли записать этому этот способ более согласовываться с тем, как это на самом деле работает:

int *a, b;

Однако я и все, которые я говорил для размышления с точки зрения типа "указателя на интервал", а не указателя на некоторые данные и тип тех данных, являемся "интервалом".

Это было просто плохим решением разработчиков C или является там некоторым серьезным основанием, почему это проанализировало этот путь? Я уверен, что на вопрос ответили прежде, но я, может казаться, не нахожу его с помощью поиска.

22
задан EMP 15 July 2010 в 23:11
поделиться

8 ответов

На веб-странице The Development of the C Language говорится: "Синтаксис этих объявлений отражает наблюдение, что i, *pi и **ppi все дают тип int при использовании в выражении". Найдите это предложение на странице, чтобы найти соответствующий раздел, в котором обсуждается этот вопрос.

17
ответ дан 29 November 2019 в 03:46
поделиться

Я могу только догадываться, почему нужно было повторять * для каждого имени переменной, упомянутого в строке, чтобы все они были указателями. Может быть, это связано с решением о согласованности языка? Позвольте мне проиллюстрировать это на примере:


Предположим, у вас есть функция foo , объявленная следующим образом:

int foo() { ... }

Давайте также предположим, что вы хотите объявить два указателя на эту функцию:

int (*fooptr1, fooptr2)();
// this doesn't work; and even if it did, what would the syntax possibly
// look like to initializing them to function foo?
// int (*fooptr1 = foo, fooptr2 = foo)() ?

int (*fooptr1)() = foo, (*fooptr2)() = foo;
// this works.

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


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

(Не забывайте, что я здесь только предполагаю.)

0
ответ дан 16 October 2019 в 03:53
поделиться

Я предполагаю, что это связано с синтаксисом полного объявления для модификаторов типа:

int x[20], y;
int (*fp)(), z;

В этих примерах кажется гораздо более очевидным, что модификаторы влияют только на одно из объявлений. Можно предположить, что когда K&R решил разрабатывать модификаторы таким образом, было «правильным» иметь модификаторы, влияющие только на одно объявление.

Кстати, я бы порекомендовал ограничиться одной переменной для каждого объявления:

int *x;
int y;
2
ответ дан 29 November 2019 в 03:46
поделиться

* изменяет имя переменной, а не спецификатор типа. В основном это связано с тем, как анализируется * . Возьмите эти утверждения:

char*  x;
char  *x;

Эти утверждения эквивалентны. Оператор * должен находиться между спецификатором типа и именем переменной (он обрабатывается как инфиксный оператор), но может располагаться по обе стороны от пробела. При этом объявление

int*  a, b;

не сделает b указателем, потому что к нему нет * . * работает только с объектами по обе стороны от него.

Также подумайте об этом так: когда вы пишете объявление int x; , вы указываете, что x является целым числом. Если y является указателем на целое число, то * y является целым числом. Когда вы пишете int * y; , вы указываете, что * y является целым числом (что вам и нужно). В операторе char a, * b, *** c; вы указываете, что переменная a , разыменованное значение b и тройное -разыменованные значения c все имеют тип char .Объявление переменных таким образом делает использование оператора звезды (почти) совместимым с разыменованием.

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

2
ответ дан 29 November 2019 в 03:46
поделиться

Потому что, если бы оператор

int* a, b;

объявлял b также как указатель, тогда у вас не было бы возможности объявить

int* a;
int  b;

в одной строке.

С другой стороны, вы можете сделать

int*a, *b;

, чтобы получить желаемое.

Подумайте об этом так: то, как оно есть сейчас, по-прежнему остается наиболее кратким и в то же время уникальным способом сделать это. Это то, о чем в основном говорит C :)

1
ответ дан 29 November 2019 в 03:46
поделиться

Декларации языка Си были написаны таким образом, чтобы "декларация зеркально отражала использование". Вот почему вы объявляете массивы так:

int a[10];

Если бы вместо этого было предложенное вами правило, где всегда

type identifier, identifier, identifier, ... ;

... то массивы логически должны были бы объявляться так:

int[10] a;

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

void foo(int a, char *b);

а не

void(int a, char* b) foo;

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


После некоторых дальнейших размышлений, я думаю, стоит также отметить, что написание "pointer to int" как "int*" в любом случае является лишь следствием "использования зеркал декларации". Если бы вы собирались использовать другой стиль объявления, то, вероятно, было бы логичнее написать "pointer to int" как "&int", или что-то совершенно другое, например "@int".

31
ответ дан 29 November 2019 в 03:46
поделиться

Может быть дополнительная историческая причина, но я всегда понимал это так:

Одно объявление, один тип.

Если здесь a, b, c и d должны быть одного типа:

int a, b, c, d;

Тогда все в строке также должно быть целым числом.

int a, *b, **c, ***d;

4 целых числа:

  1. a
  2. * b
  3. ** c
  4. *** d

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

9
ответ дан 29 November 2019 в 03:46
поделиться

Рассмотрим объявление:

int *a[10];
int (*b)[10];

Первый - это массив из десяти указателей на целые числа, второй - это указатель на массив из десяти целых чисел.

Теперь, если бы * был прикреплен к объявлению типа, было бы синтаксически неправильно помещать круглые скобки между ними. Так что вам придется найти другой способ различать эти две формы.

1
ответ дан 29 November 2019 в 03:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: