2010-10-04 17 views
6

Załóżmy, że mam dużą tablicę, którą obliczyłem i przekazuję do drugiej funkcji. Jako prosty przykład coś takiego:Czy to nieprawidłowe użycie ograniczających wskaźników?

void foo(float* array, float c, unsigned int n) 
{ 
    for (unsigned int i = 0; i < n; ++i) 
     array[i] *= c; 
} 

void bar(float* restrict array, float* restrict array2, unsigned int m, unsigned int n) 
{ 
    for (unsigned int i = 0; i < m; ++i) 
     foo(&array[i * n], array2[i], n); 
} 

Czy to złamanie zasady ograniczać w barze() gdzie można przekazać adres części tablicy do Foo(), nawet jeśli nigdy nie używać alias część tablicy wewnątrz paska()?

Odpowiedz

9

(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 Pb, Bfoo, P2array, B2bar. 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).

+1

Nie mogę powiedzieć, czy mówisz, że to dobrze, czy źle, ale rekwizyty do pełnego wdrożenia standardu. –

+0

@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

-1

Nie ograniczają oznacza, że ​​tablicy nie może alias niczego, więc można przekazać rzeczy do baru bez łamania zasad

+4

Myślę, że to pytanie wymaga cytowania ze standardowych, a nie przypadkowych wyjaśnień w stylu "ograniczenia oznacza ...". Reguły aliasingu C99 są zbyt skomplikowane, aby polegać na zwyczajnych objaśnieniach. –

+0

Zasady ograniczania są dość proste, nie można go uzyskać za pomocą niczego oprócz ogranicznika wskaźnika. – Spudd86

Powiązane problemy