Kwalifikatory typów
Kwalifikatory typu dają jedną z dwóch właściwości identyfikatorowi. const
Kwalifikator typu deklaruje obiekt, który ma być niemodyfikowalny. volatile
Kwalifikator typu deklaruje element, którego wartość może zostać odpowiednio zmieniona przez coś poza kontrolą programu, w którym się pojawia, na przykład współbieżnie wykonujący wątek.
Kwalifikatory typów, const
, restrict
i volatile
, mogą być wyświetlane tylko raz w deklaracji. Kwalifikatory typów mogą być wyświetlane z dowolnym specyfikatorem typu; nie mogą jednak pojawić się po pierwszym przecinku w deklaracji wielu elementów. Na przykład następujące deklaracje są legalne:
typedef volatile int VI;
const int ci;
Te deklaracje nie są legalne:
typedef int *i, volatile *vi;
float f, const cf;
Kwalifikatory typów są istotne tylko w przypadku uzyskiwania dostępu do identyfikatorów jako wartości l w wyrażeniach. Zobacz Wyrażenia L-Value i R-Value, aby uzyskać informacje o wartościach l i wyrażeniach.
Składnia
type-qualifier
:
const
restrict
volatile
const
i volatile
Poniżej przedstawiono deklaracje prawne i volatile
prawneconst
:
int const *p_ci; // Pointer to constant int
int const (*p_ci); // Pointer to constant int
int *const cp_i; // Constant pointer to int
int (*const cp_i); // Constant pointer to int
int volatile vint; // Volatile integer
Jeśli specyfikacja typu tablicy zawiera kwalifikatory typu, element jest kwalifikowany, a nie typ tablicy. Jeśli specyfikacja typu funkcji zawiera kwalifikatory, zachowanie jest niezdefiniowane. volatile
i const
nie mają wpływu na zakres wartości ani właściwości arytmetycznych obiektu.
Słowo
const
kluczowe może służyć do modyfikowania dowolnego typu podstawowego lub agregowanego albo wskaźnika do obiektu dowolnego typu lubtypedef
. Jeśli element jest zadeklarowany tylko z kwalifikatoremconst
typu, jego typ jest pobierany jako const int. Zmiennąconst
można zainicjować lub umieścić w regionie magazynu tylko do odczytu. Słowoconst
kluczowe jest przydatne do deklarowania wskaźników,const
ponieważ wymaga to, aby funkcja nie zmieniała wskaźnika w żaden sposób.Kompilator zakłada, że w dowolnym momencie programu
volatile
można uzyskać dostęp do zmiennej przez nieznany proces, który używa lub modyfikuje jego wartość. Niezależnie od optymalizacji określonych w wierszu polecenia kod dla każdego przypisania lub odwołania do zmiennejvolatile
musi zostać wygenerowany, nawet jeśli wydaje się, że nie ma żadnego wpływu.
Jeśli volatile
jest używany sam, int
przyjmuje się, że. Specyfikator volatile
typu może służyć do zapewnienia niezawodnego dostępu do specjalnych lokalizacji pamięci. Używanie volatile
z obiektami danych, które mogą być dostępne lub zmieniane przez programy obsługi sygnałów, przez współbieżne wykonywanie programów lub przez specjalny sprzęt, taki jak rejestry kontroli we/wy mapowane w pamięci. Zmienną można zadeklarować jako volatile
okres istnienia lub można rzutować pojedyncze odwołanie na volatile
.
- Element może być zarówno
const
elementem, jak ivolatile
, w którym przypadku element nie może zostać legalnie zmodyfikowany przez własny program, ale może zostać zmodyfikowany przez jakiś proces asynchroniczny.
restrict
restrict
Kwalifikator typu wprowadzony w języku C99 i dostępny w /std:c11
trybie lub /std:c17
może być stosowany do deklaracji wskaźników. Kwalifikuje wskaźnik, a nie to, na co wskazuje.
restrict
to wskazówka optymalizacji dla kompilatora, że żaden inny wskaźnik w bieżącym zakresie nie odnosi się do tej samej lokalizacji pamięci. Oznacza to, że tylko wskaźnik lub wartość pochodząca z niego (na przykład wskaźnik + 1) jest używana do uzyskiwania dostępu do obiektu w okresie istnienia wskaźnika. Ułatwia to kompilatorowi tworzenie bardziej zoptymalizowanego kodu. Język C++ ma równoważny mechanizm, __restrict
Należy pamiętać, że restrict
jest to kontrakt między Użytkownikiem a kompilatorem. Jeśli utworzysz alias wskaźnika oznaczonego symbolem restrict
, wynik jest niezdefiniowany.
Oto przykład, który używa elementu restrict
:
void test(int* restrict first, int* restrict second, int* val)
{
*first += *val;
*second += *val;
}
int main()
{
int i = 1, j = 2, k = 3;
test(&i, &j, &k);
return 0;
}
// Marking union members restrict tells the compiler that
// only z.x or z.y will be accessed in any scope, which allows
// the compiler to optimize access to the members.
union z
{
int* restrict x;
double* restrict y;
};