Zawsze nie byłem pewien, co oznacza słowo kluczowe ograniczające w C ++?
Czy to oznacza, że dwa lub więcej wskaźników nadanych funkcji nie nakłada się? Co to jeszcze znaczy?
c++
restrict-qualifier
Mata
źródło
źródło
restrict
to słowo kluczowe c99. Tak, Rpbert S. Barnes, wiem, że większość kompilatorów obsługuje__restrict__
. Zauważysz, że wszystko z podwójnymi podkreśleniami jest z definicji specyficzne dla implementacji, a więc NIE C ++ , ale jest wersją specyficzną dla kompilatora.#warning
dyrektywa, lub makra sygnatur funkcji (__PRETTY_FUNCTION__
w GCC,__FUNCSIG__
w MSVC itp.).restrict
nie jest uważane za słowo kluczowe C ++ (patrz en.cppreference.com/w/cpp/keyword ), a tak naprawdę jedyna wzmianka orestrict
standardzie C ++ 11 (patrz open-std.org/jtc1/sc22/wg21 /docs/papers/2012/n3337.pdf , kopia FDIS z drobnymi zmianami redakcyjnymi, § 17.2 [biblioteka.c], strona PDF 413) stwierdza, że:restrict
należy pominąć (wyłączyć, pominąć ) podpisy i semantykę funkcji standardowej biblioteki C, gdy funkcje te są zawarte w standardowej bibliotece C ++. Innymi słowy, podałem fakt, że jeśli podpis standardowej funkcji bibliotekirestrict
C zawiera C,restrict
słowo kluczowe należy usunąć z podpisu odpowiednika C ++.Odpowiedzi:
W swoim artykule „ Optymalizacja pamięci” Christer Ericson mówi, że chociaż
restrict
nie jest jeszcze częścią standardu C ++, jest obsługiwany przez wiele kompilatorów i zaleca jego użycie, gdy jest dostępne:W kompilatorach C ++, które go obsługują, prawdopodobnie powinien on zachowywać się tak samo jak w C.
Zobacz ten post SO, aby uzyskać szczegółowe informacje: Czy realistyczne jest użycie słowa kluczowego „99 ”C99?
Poświęć pół godziny na przejrzenie gazety Ericsona, jest to interesujące i warte czasu.
Edytować
Odkryłem również, że kompilator AIX C / C ++
__restrict__
IBM obsługuje słowo kluczowe .Wydaje się, że g ++ również to obsługuje, ponieważ następujący program kompiluje się czysto na g ++:
Znalazłem też fajny artykuł na temat korzystania z
restrict
:Odsłanianie słowa kluczowego Ogranicz
Edytuj2
Natknąłem się na artykuł, który konkretnie omawia użycie ograniczeń w programach C ++:
Load-hit-stores i słowo kluczowe __restrict
Microsoft Visual C ++ obsługuje również
__restrict
słowo kluczowe .źródło
#ifndef __GNUC__
#define __restrict__ /* no-op */
lub podobnie. I zdefiniuj to,__restrict
jeśli_MSC_VER
jest zdefiniowane.Jak powiedzieli inni, jeśli nic nie znaczy od C ++ 14 , rozważmy
__restrict__
rozszerzenie GCC, które robi to samo co C99restrict
.C99
restrict
mówi, że dwa wskaźniki nie mogą wskazywać na nakładające się obszary pamięci. Najczęstszym zastosowaniem są argumenty funkcji.Ogranicza to sposób wywoływania funkcji, ale pozwala na większą optymalizację kompilacji.
Jeśli dzwoniący nie przestrzega
restrict
umowy, niezdefiniowane zachowanie.Projekt C99 N1256 6.7.3 / 7 „Kwalifikatory typu” mówi:
oraz 6.7.3.1 „Formalna definicja ograniczenia” podaje krwawe szczegóły.
Możliwa optymalizacja
Przykład Wikipedia jest bardzo pouczające.
Wyraźnie pokazuje, jak pozwala zapisać jedną instrukcję montażu .
Bez ograniczeń:
Pseudo-montaż:
Z ograniczeniem:
Pseudo-montaż:
Czy GCC naprawdę to robi?
g++
4.8 Linux x86-64:Z
-O0
są takie same.Z
-O3
:Dla niewtajemniczonych konwencja wywoływania to:
rdi
= pierwszy parametrrsi
= drugi parametrrdx
= trzeci parametrWynik GCC był jeszcze wyraźniejszy niż artykuł na wiki: 4 instrukcje vs 3 instrukcje.
Tablice
Do tej pory mamy oszczędności pojedynczych instrukcji, ale jeśli wskaźnik reprezentuje tablice, które mają być zapętlone, co jest powszechnym przypadkiem użycia, wówczas można zapisać kilka instrukcji, o czym wspominają supercat i michael .
Rozważ na przykład:
Z tego powodu
restrict
inteligentny kompilator (lub człowiek) może zoptymalizować to w celu:Który jest potencjalnie znacznie bardziej wydajny, ponieważ może być zoptymalizowany pod kątem montażu w porządnej implementacji libc (takiej jak glibc) Czy lepiej jest używać std :: memcpy () lub std :: copy () pod względem wydajności? , ewentualnie z instrukcjami SIMD .
Bez ograniczenia ta optymalizacja nie byłaby możliwa, np. Rozważ:
Następnie
for
wersja tworzy:podczas gdy
memset
wersja zapewnia:Czy GCC naprawdę to robi?
GCC 5.2.1.Linux x86-64 Ubuntu 15.10:
Z
-O0
, oba są takie same.Z
-O3
:z ograniczeniem:
Dwa
memset
połączenia zgodnie z oczekiwaniami.bez ograniczeń: brak wywołań stdlib, tylko rozwijanie pętli o szerokości 16 iteracji, których nie zamierzam tu odtwarzać :-)
Nie miałem cierpliwości, by je testować, ale wierzę, że wersja z ograniczeniami będzie szybsza.
Ścisła zasada aliasingu
Słowo
restrict
kluczowe wpływa tylko na wskaźniki kompatybilnych typów (np. Dwaint*
), ponieważ surowe reguły aliasingu mówią, że aliasing niezgodnych typów jest domyślnie niezdefiniowanym zachowaniem, więc kompilatory mogą założyć, że tak się nie dzieje i zoptymalizować.Zobacz: jaka jest ścisła zasada aliasingu?
Czy to działa w odniesieniu do referencji?
Zgodnie z dokumentacją GCC robi to: https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gcc/Restricted-Pointers.html ze składnią:
Istnieje nawet wersja
this
funkcji członkowskich:źródło
-fno-strict-aliasing
, to nierestrict
powinno robić różnicy między wskaźnikami tego samego typu lub różnych typów, nie? (Mam na myśli „restrict
znaczy coś w C ++. Jeśli wywołasz funkcję biblioteki C zrestrict
parametrami z programu C ++, musisz przestrzegać jej konsekwencji. Zasadniczo, jeślirestrict
jest używany w interfejsie API biblioteki C, oznacza to coś dla każdego dzwoniącego z dowolnego języka, w tym dynamicznego FFI z Lisp.Nic. Został dodany do standardu C99.
źródło
restrict
słowa kluczowego. Dlatego moja odpowiedź jest prawidłowa. Opisujesz zachowanie specyficzne dla implementacji i coś, na czym tak naprawdę nie powinieneś polegać.To jest oryginalna propozycja dodania tego słowa kluczowego. Jak jednak wyraźnie zaznaczono, jest to funkcja C99 ; nie ma to nic wspólnego z C ++.
źródło
__restrict__
słowo kluczowe, które jest identyczne, o ile wiem.restrict
. Zachowanie programu C ++ staje się niezdefiniowane, jeśli narusza ograniczenia implikowane przezrestrict
.restrict
słowo kluczowe. Oczywiście, jeśli przekażesz aliasy wskaźników do funkcji C, która deklaruje, że są ograniczone (co możesz zrobić zarówno z C ++, jak i C), to jest niezdefiniowana, ale to zależy od ciebie.restrict
. Zachowanie programu C ++ staje się niezdefiniowane, jeśli narusza ograniczenia wynikające z ograniczenia. Ale tak naprawdę nie ma to nic wspólnego z C ++, ponieważ jest „na ciebie”.W C ++ nie ma takiego słowa kluczowego. Lista słów kluczowych C ++ znajduje się w sekcji 2.11 / 1 standardu języka C ++.
restrict
jest słowem kluczowym w wersji C99 języka C, a nie w C ++.źródło
__restrict__
słowo kluczowe, które jest identyczne, o ile wiem.Ponieważ pliki nagłówkowe z niektórych bibliotek C używają słowa kluczowego, język C ++ będzie musiał coś z tym zrobić .. przynajmniej, ignorując słowo kluczowe, więc nie musimy # definiować słowa kluczowego do pustego makra, aby stłumić słowo kluczowe .
źródło
extern C
deklaracji lub po cichu upuszczane, jak ma to miejsce w przypadku kompilatora AIX C / C ++, który zamiast tego obsługuje__rerstrict__
słowo kluczowe. To słowo kluczowe jest również obsługiwane w gcc, dzięki czemu kod będzie kompilować to samo w g ++.