Почему эта инициализация принимается компилятором С++? static int x = x;

Я только что узнал об этом:

static int x = x;

Почему эта инициализация принята компилятором C++?

Я бы назвал это аномалией компилятора, но кто-то может прийти с хорошим объяснением этого.

Таким образом, для данных со статическим хранилищем можно инициализировать переменную самой собой... Я пробовал это с помощью компиляторов VS2015 и VS2017, а также некоторых других онлайн-компиляторов C++.

Ответ 1

Это фактически то же самое для переменных static и non static.

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

static int x = x;

имя x становится видимым сразу после его первого вхождения и может упоминаться в инициализаторе. Поскольку он статический, его начальное значение хорошо определено (оно 0).

Это также законно, даже в области блока:

int x = x;

хотя здесь вы, вероятно, получите предупреждение, потому что x инициализируется с собственным неопределенным значением (в большинстве случаев поведение undefined).

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

void *p = (void*)&p;

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

Ответ 2

Если вы хотите запретить все глупые конструкции в C++ (и C тоже в этом отношении), вы получите довольно длинный список.

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

Многие из этих странных вещей можно проследить до C, и C - это язык, который предъявляет мало требований к компилятору, но предъявляет больше требований к программисту. Многие конструкции дают неопределенное поведение или неопределенное значение. Для этого есть две основные причины. Во-первых, это облегчает правильную запись компилятора и низкие системные требования. Это было важно в первые годы существования C. Этот язык появился в 1972 году, то есть за 8 лет до того, как Commodore выпустила домашний компьютер VIC-20 с 4 КБ памяти. Во-вторых, это позволяет компилятору генерировать более быстрый код с меньшим использованием памяти, что, как только что упоминалось, было очень важным в прошлом.

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

Как упомянул Кит в своем ответе, если переменная является статической, то она будет иметь значение 0, что означает, что значение не является неопределенным. Результат static int x = x; совершенно понятно, так зачем это запрещать? Вы могли бы сделать спецификацию C++ больше и труднее поддерживать и, возможно, сломать какой-то старый код, просто чтобы решить что-то, что не является проблемой.

Когда дело доходит до нестатических переменных, это другая вещь, потому что значение является неопределенным. Здесь есть лучшая причина запретить эту конструкцию, но, с другой стороны, вы уже получили предупреждение за нее. По крайней мере, если вы используете -Wall, что вы должны. Я мог бы также добавить, что многие предупреждения - это предупреждения, а не ошибки, чтобы не сломать старый код. Но вместо того, чтобы запрещать инициализацию для себя, было бы более разумно полностью запретить использование неинициализированных переменных.