Почему имена массивов регистров можно назначать переменным-указателям без ошибок компилятора? - PullRequest
3 голосов
/ 25 сентября 2019

У меня вопрос по поводу ключевого слова register в C.

Я обнаружил, что register имя массива (например, array) может быть назначено переменной указателя, в то время как &array[0] не может быть.

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

Вот что я попробовал:

Я прочитал cppreference , который объясняет ключевое слово register и говорит:

массивы регистров не могут быть преобразованы в указатели.

Также я читаю черновик C89, в котором говорится:

Реализация может обрабатывать любое объявление регистра просто какАвто декларация.Однако, независимо от того, используется ли на самом деле адресуемое хранилище, адрес любой части объекта, объявленной с помощью регистра спецификатора класса хранилища, не может быть вычислен , либо явно (с использованием унарного оператора &, как обсуждалось в3.3.3.2) или неявно (путем преобразования имени массива в указатель, как описано в 3.2.2.1). Таким образом, единственный оператор, который может быть применен к массиву, объявленному с помощью регистра спецификатора класса хранения, - это sizeof.

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

Кроме того, чтобы найти ответ, я искал здесь и нашел этот вопрос: Адрес регистровой переменной .Есть хорошие ответы, однако я так и не смог найти ответ, который хотел.

Вот код, который я тестировал.Я скомпилировал этот код через Clang с флагом -std=c89:

register int array[10];
int* p;

p = array;     // Compiled without warning or error
p = &array[0]; // Compiled with error which I expected

Я ожидал, что и p = array;, и p = &array[0]; вызвали скомпилированную ошибку, но только p = &array[0]; допустил ошибку компиляции.

1 Ответ

3 голосов
/ 25 сентября 2019

Это ошибка в компиляторе Clang. GCC показывает ошибку в обеих строках.

При обсуждении автоматического преобразования «массива типа » в «указатель на тип »,C 2018 6.3.2.1 говорит:

… Если объект массива имеет класс хранения регистров, поведение не определено.

Далее, сноска C 2018 124 говорит:

… адрес любой части объекта, объявленной со спецификатором класса хранения register, не может быть вычислен ни явно (с помощью унарного оператора &, как описано в 6.5.3.2), ни неявно(путем преобразования имени массива в указатель, как описано в 6.3.2.1)…

Очевидно, p = array; преобразует array в указатель, как обсуждалось в 6.3.2.1, но эта сноска (который является ненормативным, но в явном виде сообщает нам намерение в этом случае) говорит, что значение для этого указателя не может быть вычислено.

Поскольку поведение не определено стандартом C, реализация C может определить его какрасширение.Однако противоречивое поведение между array и &array[0] говорит о том, что это не преднамеренное расширение Кланга, а ошибка.

...