int **restrict
только утверждает, что память, адресуемая Out, A и B, не перекрывается (за исключением того, что A и B могут перекрываться, если ваша функция не изменяет ни одну из них). Это означает массивы указателей. Он ничего не говорит о содержимом памяти, на которое указывают Out, A и B. Сноска 117 в n1124 гласит:
если идентификатор p имеет тип (int
** ограничение), тогда выражения указателя p и p + 1 основаны на
обозначенный объект ограниченного указателя
по р, но указатель выражений * р
и p [1] не являются.
По аналогии с const
, я подозреваю, что квалификация с restrict
дважды будет утверждать, что вы хотите, то есть, что ни одно из значений в массиве не указывает на перекрывающуюся память. Но, читая стандарт, я не могу доказать себе, что это действительно так. Я считаю, что «Пусть D будет объявлением обычного идентификатора, который обеспечивает средство обозначения объекта P как ограниченного указателем типа T», действительно означает, что для int *restrict *restrict A
, тогда A [0] и A [1 ] - объекты, обозначенные как ограниченный указателем на int. Но это довольно тяжелый легальный.
Я понятия не имею, будет ли ваш компилятор что-нибудь делать с этими знаниями, заметьте. Ясно, что это возможно, вопрос в том, реализовано ли это.
Так что я действительно не знаю, что вы получили по сравнению с обычным C 2-D массивом, где вы просто выделяете rows * cols * sizeof(int)
и индексируете с помощью A[cols*row + col]
. Тогда вам явно нужно только одно использование restrict, и любой компилятор, который делает что-либо с restrict
, сможет переупорядочивать операции чтения из A и B через записи в Out. Без restrict
, конечно, это не может, поэтому, делая то, что вы делаете, вы полагаетесь на милость вашего компилятора. Если он не может справиться с двойным ограничением, только с одним ограниченным случаем, то ваше двойное косвенное обращение обойдется вам в оптимизации.
На первый взгляд, умножение скорее всего будет быстрее, чем дополнительное перенаправление указателя в любом случае. Вы, очевидно, заботитесь о производительности или вообще не будете использовать ограничение, поэтому я бы довольно тщательно протестировал производительность (на всех нужных вам компиляторах), прежде чем вносить это изменение ради немного более приятного синтаксиса и не вспоминать, сколько столбцы есть в вашем массиве каждый раз, когда вы обращаетесь к нему.
имеет доступ к элементам через A [0] [col * nrows + row] undefined?
Да, если элемент изменен одним из обращений, потому что это делает A [0] псевдонимом для памяти, к которой также осуществляется доступ через A [col]. Это было бы хорошо, если бы только A и B были указателями с ограниченным ограничением, но не если A [0] и A [col].
Я предполагаю, что вы не модифицируете A в этой функции, так что на самом деле псевдоним в порядке. Если бы вы сделали то же самое с Out, поведение было бы неопределенным.