2015-08-31 1 views
3

Глядя на С11 6.3.2.1 пункта 3:Почему индексирование массива регистра не определено?

исключением случаев, когда это операнд оператора sizeof, оператор _Alignof или унарный оператор &, или строковый литерал используется для инициализации массива, выражение, которое имеет тип «массив типа», преобразуется в выражение с типом «указатель на тип», который указывает на начальный элемент объекта массива и не является значением lvalue. Если объект массива имеет класс хранения register, поведение не определено.

Неопределенное поведение кажется странным выбором для этой ситуации. Неопределенное поведение «не предъявляет требований» (3.4.3). Другими словами, согласно только формулировке 6.3.2.1, индексирование (или выполнение нескольких других операций с) массива, объявленного с помощью register, предположительно разрешено компилировать, запускать и выполнять именно то, что код выглядит так, как без него ошибка.

register int a[5]; 
a[0] = 6; // apparently not required to cause an error? 

Это, кажется, противоречит духу ключевому слову, которое (в 6.5.3.2) предотвращает адрес именующей в настоящее время принимается с &. Это не совсем то же самое, но это, безусловно, связано, как неявное преобразование указателя на массив-> и & на lvalue, генерирует такой же результат: указатель на хранилище объекта.

В сноске к 6.7.1 делает эту связь явной:

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

Так что, если он «не может» быть сделано, почему это преобразование ип определяется вместо ошибочны, или (для индексации, где есть несколько других вариантов) от реализации?

Он не читается как надзор в 6.3.2.1, поскольку значение register достаточно прост в соответствии с другими упоминаниями; Я бы предположил, что это было совершенно четко, если бы в этом предложении не говорилось иначе. В чем сомневаться?

+0

Связано с [Возможно сохранение целого массива в регистре cpu] (http://stackoverflow.com/q/17342881/1708801), я недавно видел этот вопрос, хотя я не могу вспомнить, почему. –

+0

Интересно, было ли намерение разрешать расширения, но не накладывать никаких требований на их точное значение?Существует много ситуаций, когда C страдает от того, что не имеет термина, значение которого менее жестко, чем определено в Реализации (которое требует, чтобы реализации указывали что-либо) или Unspecified (что требует выбора из фиксированного набора вариантов), но не так свободно, как Undefined (все идет). Лично я считаю, что 'register' может быть полезным ключевым словом, если функция, которая приняла параметр типа' register int * ', обещала не сохранять указатель и, следовательно, вызывающие функции такого типа ... – supercat

+0

... может содержать переменные адрес которого был передан этой функции (но не был вообще открыт), мог сохранить эти переменные в кешках в регистрах при вызове других функций (которые могли бы, но для ключевого слова register *, иметь доступ к указателям, сохраненным более ранними вызовами функций). – supercat

ответ

1

Помните, что Undefined Behavior позволяет всем, в том числе «вести себя так, как ожидается на конкретной платформе». То есть для платформы, на которой есть регистры аппаратного массива, вы должны были бы сделать для компиляции, для платформы, которую вы не хотите компилировать. Оставляя его, UB позволяет обоим.

IIRC a 6502 имеет 256 регистров с отображением памяти в начале адресного пространства.

+0

Большинство инструкций 6502 имели режим адресации, который предполагал бы, что верхний байт адреса равен нулю, т.е. «lda 57» будет принимать только два байта, а не три. Кроме того, существуют режимы косвенной адресации, которые будут извлекать два байта из любых двух последовательных ячеек памяти в течение первых 256 и использовать их значения в качестве младших и высоких байтов адреса. Хотя это означало, что адреса нулевой страницы можно использовать для целей, аналогичных адресным регистрам на других машинах, обращения к этим адресам поступали на шину внешней памяти, как и любая другая. 6510 найден в ... – supercat

+0

... Commodore 64 добавил порт ввода-вывода с регистром направления данных по адресу $ 0000 и регистра данных по адресу $ 0001; Я думаю, что идея состояла в том, чтобы позволить 64 КБ адресного пространства быть банкоматом полностью как ОЗУ, без необходимости резервировать банк адресов для устройств ввода/вывода, контролирующих сопоставление памяти, но вводя общий порт ввода-вывода в ЦП кажется любопытным подходом. – supercat