Инициализация круговых данных в C. Является ли это действительным кодом C в соответствии с любым стандартом?
Я хотел посмотреть, могу ли я инициализировать глобальную переменную, указывающую на себя:
#include <stdio.h>
struct foo { struct foo *a, *b; } x = { &x, &x };
int main()
{
printf("&x = %p, x.a = %p, x.b = %p\n", &x, x.a, x.b);
return 0;
}
Этот код компилируется и выполняется, как ожидалось, с помощью gcc
(все три указателя печатаются одинаково).
Я хочу знать:
- Является ли это надежным?
- Этот стандарт?
- Является ли это переносной?
РЕДАКТИРОВАТЬ: Чтобы уточнить, я задаю вопрос о доступности адреса x
в своем собственном инициализаторе.
Ответы
Ответ 1
Это стандартный код C.
Этот параграф могучего Стандарта разрешает это (внимание мое):
(C99, 6.2.1p7) "Теги структуры, объединения и перечисления имеют область видимости, которая начинается сразу после появления тега в спецификаторе типа, который объявляет тег. Каждая константа перечисления имеет область, которая начинается сразу после появления его определяющий перечислитель в списке перечислений. Любой другой идентификатор имеет область видимости, которая начинается сразу после завершения его объявления."
Для информации обратите внимание, что для иллюстрации последнего предложения 6.2.1p7 в книге "Новый стандарт C" Дерека М. Джонса используется пример, аналогичный вашему:
struct T {struct T *m;} x = /* declarator complete here. */ {&x};
Ответ 2
Да ко всему вышесказанному. У вас есть пара указателей, которые вы инициализируете одним и тем же адресом, поэтому они содержат один и тот же адрес и то же, что и адрес, с которым вы их инициализировали.
Возможно, более интересно, x.a
также гарантированно указывает на себя (т.е. первый элемент в структуре гарантированно находится в самом начале структуры, поэтому указатель на структуру, преобразованный в тип первый элемент гарантированно указывает на этот первый элемент.