2013-09-26 22 views
11

Czy istnieje sposób, aby powiedzieć kompilatorowi C99, że jedynym sposobem uzyskania dostępu do danej tablicy jest użycie myarray [indeks]? Powiedz coś takiego:Używanie ograniczeń z tablicami?

int heavy_calcualtions(float* restrict range1, float* restrict range2) 
{ 
    float __I promise I won't alias this__ tmpvalues[1000] = {0}; 

    .... 
    heavy calculations using range1, range2 and tmpvalues; 
    .... 
} 

Korzystając ograniczać Obiecałam, że nie będę alias Zakres1 i zakres2 ale jak mam zrobić to samo dla tablicy deklarowane wewnątrz mojej funkcji?

+0

Jakiego rodzaju ostrzeżenie to rzuca? – dhein

+1

"nieprawidłowe użycie ograniczeń" - powinno być używane ze wskaźnikami, a nie tablicami (o ile rozumiem). Mogę zrobić float * ograniczyć tmpvalues ​​= malloc (sizeof (float) * 1000), ale nie przydzielam na stos, który może mieć wpływ na wydajność. Poza tym mówienie kompilatorowi, że dostęp do indeksów tablic jest bezpieczny (więc nie potrzeba żadnych odczytów defensywnych) wydaje się bardzo naturalnym rozszerzeniem ograniczenia użycia przy pomocy wskaźników, więc intuicyjnie musi być sposób na zrobienie tego. –

+1

Zrobiłem: float * restrict tmpvalues ​​= alloca (sizeof (float) * 1000); memset (tmpvalues, 0, sizeof (float) * 1000); i to jest mierzalna poprawa ale wolałbym robić to w standardzie (jak w drodze reklamacji C99) –

Odpowiedz

3

Dlaczego nie możesz wykonać następujące czynności? Nie uzyskujesz dostępu do danych związanych z tmpvalues za pośrednictwem tej zmiennej, więc można użyć wskaźnika ograniczającego w części kodu wymagającej dużej mocy obliczeniowej.

#include <stdio.h> 
#include <stdlib.h> 

int heavy_calcs(int n, float* restrict range1, float* restrict range2) 
{ 
    if (n>1000) return 1; 
    float tmpvalues[1000] = {0}; 
    { 
     float * restrict ptv = tmpvalues; 
     for (int i=0; i<n; i++) { 
      ptv[i] = range1[i] + range2[i]; 
     } 
    } 
    return 0; 
} 

int main(int argc, char * argv[]) 
{ 
    int n = (argc>1) ? atoi(argv[1]) : 1000; 
    float * r1 = (float*)malloc(n*sizeof(float)); 
    float * r2 = (float*)malloc(n*sizeof(float)); 
    int rc = heavy_calcs(n,r1,r2); 
    free(r1); 
    free(r2); 
    return rc; 
} 

Uruchomiłem to przez kompilator Intel 15 i nie było problemu z wektoryzowaniem pętli. To prawda, że ​​ta pętla jest trywialna w porównaniu z tym, co zakładam, że twoja jest, więc twój przebieg może się różnić.

+0

[Nie trzeba rzucać wyniku 'malloc' w C] (http: // stackoverflow.com/q/605845/995714) –

+1

Nie ma również potrzeby przypisania '{}' wokół przypisania 'ptv'. – Jeff

10

Chociaż odpowiedź Jeffa jest prawidłowa, tzn. Zawsze można utworzyć wskaźnik do przydzielonej tablicy, faktem jest, że kompilator zna podczas kompilacji, że wartości tmp nie będą aliasowane, ponieważ zmienna jest zadeklarowana jako faktyczna tablica, a nie wskaźnik. Jedyną szansą na alias tablicy jest deklaracja do niej, więc jeśli tego nie zrobisz, nie musisz deklarować jej jako restrict. Jest to bardziej oczywiste, jeśli tmpvalues jest jedyną zmienną, jaką będziesz mieć w funkcji.

Problem może pojawić się, jeśli przechodzą wskaźnik do innej funkcji, to nie należy stwierdzić, czy odebrany wskaźnik jest ograniczony lub nie.

Dokumentacja natknąłem związanych z tym tematem obejmuje C99:

Niech D będzie deklaracja zwykłego identyfikatora, który zapewnia środki wyznaczenia obiektu P jako wskaźnik ograniczenia zakwalifikowanych do typu T

Należy pamiętać, że dotyczy to tylko wskaźników.

z TI zapewnia pewne wskazówki dotyczące dostrajania wydajności za pomocą słowa kluczowego restrict. Oprócz wszystkich wskazówek, rozdział 3.3 podaje przykłady, kiedy można zastosować kwalifikator tego typu, a kiedy nie. Poszukaj deklaracji tablicy x na środku strony 16, która stwierdza, że ​​nie deklaruje wskaźnika, a zatem nie może być zastrzeżona.

+0

Jeśli wskaźnik do tablicy zostanie przekazany do kodu zewnętrznego, nie ma żadnego czystego sposobu na wskazanie, że kod zewnętrzny nie będzie przechowywać kopii wskaźnika i użyje tej kopii do arbitralnych celów, gdy następnym razem zostanie wywołany kod zewnętrzny. IMHO byłoby pomocne, gdyby C miał kwalifikator podobny do "ograniczenia", ale do użycia ze zmiennymi, których adres został zajęty, ale będzie używany tylko w bardzo ograniczonym zakresie, ale żadna taka funkcja nie jest zdefiniowana. – supercat

+0

@supercat problemem jest - jak definiujesz te "różne sposoby"? gcc ma atrybuty (takie jak "czysty"), które mogą być dołączone do funkcji, które obiecują, że funkcja nie zrobi pewnych klas rzeczy. Poza tym mamy teraz "optymalizację czasu łącza", gdzie zestaw narzędzi kompilatora może zasadniczo sprawdzić, co faktycznie robi ta funkcja, i wykorzystać te informacje. – greggo

+0

@greggo: Gdybym pisał reguły, powiedziałbym, że obiekt "register" może mieć tylko swój adres wzięty pod ocenę argumentu funkcji, a zachowanie byłoby zdefiniowane tylko w przypadkach, w których wszystkie zastosowania wynikowego wskaźnik lub wskaźniki z nich wyprowadzone występują przed zwróceniem funkcji, a podczas wykonywania funkcji (1) dostęp do obiektu odbywa się wyłącznie za pomocą wskaźnika wynikowego lub innych pochodnych od niego, lub (2) obiekt nie jest modyfikowany w żaden sposób. Jeśli rozpocznie się proces budowania, budując listę wszystkich zewnętrznych symboli używanych w każdej funkcji ... – supercat

Powiązane problemy