Подтвердить что ты не робот

Почему синтаксис объявления переменных С++ несовместим?

когда я объявляю переменные С++, я делаю это следующим образом:

int a,b,c,d;

или

string strA,strB,strC,strD;

I.e., сначала тип, затем список имен переменных, разделенный запятыми.

Однако я указываю такие указатели:

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

и ссылки вроде этого:

int &a,&b,&c,&d;

Чтобы быть последовательным, он должен быть

int* a,b,c,d;

и

int& a,b,c,d;

Почему это не согласовано?

4b9b3361

Ответ 1

Это из-за наследия C. Модификатор * применяется к переменной в C. Поэтому разработчики С++ сделали & применимым к переменной, а также по аналогии, поскольку они не могли изменить первый, не нарушая совместимость C. То же самое верно и для синтаксиса массива:

int anInt, *aPointerToInt, anArrayOfInt[100];

В дизайне и эволюции С++ Bjarne Stroustrup говорит, что он не был доволен этим, но должен был принять его для совместимости с C. В частности, он был недоволен этим:

int *a[10];

Из декларации не видно, если a является указателем на массив или массив указателей (это массив указателей, вам нужно скобки для переопределения).

Конечно, вы всегда можете использовать typedef для очистки вещей немного.

Ответ 2

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

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

Например,

int *a, b;
...
*a = 42;
b = 314159;

... использование a и b похоже на объявление a и b.

Там даже упоминается такое поведение от Денниса Ритчи, одного из создателей C:

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

  • Деннис Ричи, Разработка языка C. История языков программирования - II изд. Томас Дж. Бергин-младший и Ричард Г. Гибсон-младший ACM Press (Нью-Йорк) и Эддисон-Уэсли (Reading, Mass), 1996; ISBN 0-201-89502-1.

Ответ 3

Причина такова: на самом деле & и * в C и С++ применяются к переменной и no для ввода.

Итак, проблема в том, что если вы хотите объявить 4 указателя на целые числа, вы должны написать

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

Написание int* a, b; означает

int *a;
int b;

По этой причине многие люди предпочитают писать int *a;, чем int* a;, просто стиль кода.

Конечно, int* - это тип, но синтаксис C четко указывает, что в объявлении переменной * и & применится к переменной.

Это происходит по той же причине, что массивы в C объявлены таким образом:

int a[10], b;

std::cout << typeid(a).name() << std::endl; // it will print int[10]
std::cout << typeid(b).name() << std::endl; // it will print int

В других языках, таких как С#, вместо этого используется синтаксис int[] array;.

Еще одна вещь - указатель на синтаксис функции:

// Now we declare a variable that is a pointer to function
int (*pt2Function)(char, char) = NULL;

Мы применяем * к имени переменной.

Мне кажется, что использование * и & применимо к переменной, также если 90% из нас предпочли бы по-другому, более соответствует остальной части языка.

Точно так же, возвращаясь к массивам:

// Now we declare a variable that is a pointer to an array of 10 integers.
int (*arrayptr)[10];

Ответ 4

C имеет правило для своих объявлений: декларации имитируют использование. Это означает, что декларация для переменной выглядит так, как используется переменная. Например:

int i;

Использование этой переменной выглядит как i, и это выражение приводит к int.

int *i;

Использование этой переменной выглядит как *i, и это выражение приводит к int. Это также означает, что выражение i приводит к указателю на int.

int i(void);

Использование этой переменной выглядит как i() и приводит к int. Это также означает, что i - это функция, которая ничего не принимает и возвращает int.

int (*i[5])();

Использование этой переменной выглядит как (*i[x])() и приводит к int. Это также означает, что *i[x] - это функция, возвращающая int, а i[x] - указатель на функцию, возвращающую int, а i - массив указателей на функции, возвращающие int.

Итак:

int a, *b, c(void), (*d[5])(void);

объявляет несколько выражений, все из которых имеют тип int, но сами переменные не все int s.

N.B. в объявлениях функций и массивов вспомогательные объявления не в буквальном смысле напоминают использование переменной. То есть int i[5]; не означает, что вам нужно поставить "5" в квадратные скобки, когда вы используете i, а int i(int); не означает, что вы вызываете функцию, говоря i(int);. Также объявления переменных типов структуры не соответствуют их использованию, поскольку вам придется объявлять выражения для каждой переменной-члена.

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

typedef int (*array_of_function_pointers[5])(void);

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

Ответ 5

С++ унаследовал этот синтаксис из C. Книга K & R (§5.1) говорит, что выражение

int *ip, **ipp;

предназначен для мнемоники (т.е. вы читаете "*ip и **ipp имеют тип int" ), они хотели, чтобы он имитировал синтаксис использования.

Я согласен, что это довольно загадочно и противоречиво для людей и несовместимо с typedefs, например.

typedef int* intptr;
intptr a, b; // equivalent to: int *a, *b

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