2015-12-15 12 views
15

Często używana instrukcja, taka jak (void)x;, pozwala ukryć ostrzeżenia o nieużywanej zmiennej x. Ale gdy próbuję kompilacji następuje, mam pewne rezultaty ja nie bardzo rozumiem:Co naprawdę robi casting do `void`?

int main() 
{ 
    int x; 
    (short)x; 
    (void)x; 
    (int)x; 
} 

Kompilacja ta z g ++, dostaję następujące ostrzeżenia:

$ g++ test.cpp -Wall -Wextra -o test 
test.cpp: In function ‘int main()’: 
test.cpp:4:13: warning: statement has no effect [-Wunused-value] 
    (short)x; 
      ^
test.cpp:6:11: warning: statement has no effect [-Wunused-value] 
    (int)x; 
     ^

więc stwierdzić, że rzucając się void różni się bardzo od rzutowania do innych typów, być typem docelowym takim samym jak decltype(x) lub czymś innym. Domyślam się możliwych wyjaśnień jest:

  • Jest to tylko konwencja, że ​​(void)x; ale nie inne odlewy wstrzyma ostrzeżenia. Wszystkie stwierdzenia jednakowo nie mają żadnego efektu.
  • Ta różnica jest w jakiś sposób związana z faktem, że void x; nie jest prawidłową instrukcją, gdy short x; jest.

Które z poniższych stwierdzeń są bardziej poprawne? Jeśli nie, to w jaki sposób można wyjaśnić różnicę w ostrzeżeniach kompilatora?

+2

Jest to tylko konwencja między kompilatory, że ta obsada Pomija ostrzeżenia. Standard C++ nie wspomina o ostrzeżeniach, ponieważ "instrukcja nie ma żadnego efektu". –

Odpowiedz

20

Przesyłanie do pustej przestrzeni służy do tłumienia ostrzeżeń kompilatora. Standard mówi w §5.2.9/4 mówi

Każda ekspresja może być bezpośrednio przekształcony do typu „CV void”. Wartość ekspresja jest odrzucany.

8

To stwierdzenie:

(void)x; 

mówi "Ignoruj ​​wartość x." Nie ma takiego typu jak void - jest to brak typu. Więc to bardzo różni się od tego:

(int)x; 

Który mówi "Traktuj x tak, jakby był liczbą całkowitą". Gdy wynikowa liczba całkowita zostanie zignorowana, pojawi się ostrzeżenie (jeśli jest włączone).

Kiedy ignorujesz coś, co jest niczym, GCC nie uważa go za problem - i nie bez powodu, ponieważ casting to void jest idiomatycznym sposobem zignorowania zmiennej jawnie w C i C++.

+0

Nigdy nie myślałem o tym w ten sposób, ale jestem nieco zdezorientowany, czy myślisz, że mógłbyś podać przykład wyjaśniający koncepcję rzucania zmiennej do "pustki"? – Sacert

+4

Jestem prawie pewien, że istnieje "taki typ jak" void ". Zobacz [basic.types]. –

+0

@Sacert: '(void) x' rzuca zmienną do unieważnienia. Sam to powiedziałeś. Ale kiedy już to zrobisz, nie możesz nic więcej z nim zrobić, ponieważ puste wyrażenie nie ma żadnej wartości. –

4

Standard nie wymaga generowania ostrzeżenia ("diagnostyka" w standardese) dla nieużywanych zmiennych lokalnych lub parametrów funkcji. Podobnie nie nakazuje, aby takie ostrzeżenie zostało zniesione. Przesyłanie zmiennego wyrażenia do void w celu powstrzymania tego ostrzeżenia stało się idiomem w społeczności C i późniejszej C++, ponieważ wynik nie może być w żaden sposób wykorzystany (poza np. (int)x), więc jest mało prawdopodobne, że odpowiedni kod właśnie zniknął. Np:

(int)x; // maybe you meant f((int)x); 
(void)x; // cannot have intended f((void)x); 
(void)x; // but remote possibility: f((void*)x); 

Osobiście uważam tę konwencję zbyt niejasne jeszcze, dlatego wolę używać szablonu funkcję:

template<typename T> 
inline void ignore(const T&) {} // e.g. ignore(x); 

idiomatyczne sposób zignorować parametrów funkcji jest jednak pominąć ich imię (jak widać powyżej).Często używam tej funkcji, gdy potrzebuję móc nazwać parametr funkcji w warunkowo skompilowanym kodzie, takim jak assert. Znajduję np. następujące bardziej czytelny niż stosowanie #ifdef NDEBUG:

void rate(bool fantastic) 
{ 
    assert(fantastic); 
    ignore(fantastic); 
} 
+1

Od C++ 17 możesz używać atrybutu [[perhaps_unused]] zamiast wszystkich "kreatywnych" sposobów ignorowania parametru. – Ruslan