(Wszystkie cytaty odnoszą się do N1256, który jest C99 oraz sprostowania techniczny (TC3)).
Formalna definicja restrict
podana jest w §6.7.3.1. Zacytuję najważniejsze podrozdziały poniżej. P
to restrict
- zastrzeżony wskaźnik dla typu T
, którego zasięg to blok B
. Wyrażenie wskaźnika E
jest określane jako na podstawieP
, jeśli zależy ono od wartości samego P
, a nie wartości, którą wskazuje P
.
W każdym wykonaniu B
niech L
być dowolny lwartość który ma &L
oparciu P. Jeśli L
jest używany do uzyskania dostępu do wartości obiektu X
że określa i X
również zmodyfikowane (bez względu na sposób) , następnie obowiązują następujące wymagania:
T
nie będzie miał stałych wartości.
- Każda inna l-wartość używana do uzyskania dostępu do wartości
X
będzie miała również swój adres na podstawie P
.
- Każdy dostęp modyfikujący
X
będzie również uważany za modyfikujący P
, dla celów niniejszego podrozdziału.
- Jeśli
P
przypisywana jest wartość wyrażenia wskaźnik E
, który jest oparty na innym ograniczonym wskaźnik obiektu P2
, związany z blokiem B2
, wówczas wykonanie B2
powinna rozpocząć się przed wykonaniem B
lub wykonanie B2
wygasa przed przydzieleniem.
Jeśli te wymagania nie są spełnione, zachowanie jest niezdefiniowane.
Przyjrzyjmy się, jakie zasady mają do powiedzenia o dostęp do części bar
„s array
w foo
. Zaczynamy od array
, ograniczonego kwalifikowanego wskaźnika zadeklarowanego na liście parametrów bar
. Dla jasności, ja alfa-konwersji parametrów foo
:
void foo(float* b, float c, unsigned int n) { /*modify b[i]*/ }
Przechowywanie wskazywanego przez array
być także modyfikowane przez b
. To jest w porządku z drugim punktem, ponieważ &array[i*n]
jest odpowiednikiem array+(i*n)
(patrz §6.5.3.2).
Jeśli b
było ograniczyć wykwalifikowanych, wtedy musielibyśmy sprawdzić podpunkt czwarty z P
← b
, B
← foo
, P2
← array
, B2
← bar
. Od B
jest zagnieżdżony wewnątrz B2
(funkcje zachowują się tak, jak tutaj opisane, patrz §6.7.3.1.11), pierwszy warunek jest spełniony. Istnieje również jedna instancja trzeciej punktor (dostęp do b[i]
w foo
), która nie stanowi problemu.
Jednak wartość b
nie jest ograniczona. Zgodnie z § 6.3.3.2.2, "W przypadku jakiegokolwiek kwalifikatora q, wskaźnik do innego niż zastrzeżony typ q może zostać przekonwertowany do wskaźnika na wersję tego typu; wartości przechowywane w oryginalnych i skonwertowanych wskaźnikach powinny być równe ". Dlatego konwersja z array+(i*n)
na b
jest dobrze zdefiniowana i ma oczywiste znaczenie, więc definiowane jest zachowanie programu. Ponadto, ponieważ b
nie jest restrict
- kwalifikowany, nie musi spełniać żadnych warunków liniowości. Na przykład, następujący foo
jest legalne w połączeniu z bar
:
void qux(float *v, float *w) {
v[0] += w[0];
}
void foo(float* b, float c, unsigned int n)
{
qux(b,b);
}
DODANO: W celu rozwiązania konkretnego zaniepokojenie „w pasku() gdzie można przekazać adres części tablicy do Foo () ", To nie jest problem: restrict
dotyczy wskaźnika, nie tablicy, i można na nim wykonać arytmetykę (punkt 2).
Nie mogę powiedzieć, czy mówisz, że to dobrze, czy źle, ale rekwizyty do pełnego wdrożenia standardu. –
@Matt: Kod jest poprawny (częściowo dlatego, że reguły ograniczające nie powodują zbyt wiele tutaj, a częściowo dlatego, że możesz zamienić ogranicznik ograniczający w podskoku ograniczonym przez 'foo'). – Gilles