2015-12-15 24 views
15

Một câu lệnh thường được sử dụng như (void)x; cho phép chặn cảnh báo về biến không sử dụng x. Nhưng nếu tôi cố gắng biên soạn sau đây, tôi nhận được một số kết quả tôi không hoàn toàn hiểu:Việc truyền tới `void` thực sự là gì?

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

Biên dịch này với g ++, tôi nhận được những lời cảnh báo sau đây:

$ 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; 
     ^

Vì vậy, tôi kết luận rằng đúc để void rất khác với việc truyền sang bất kỳ loại nào khác, là loại mục tiêu giống như decltype(x) hoặc một cái gì đó khác. Dự đoán của tôi tại các giải thích có thể có là:

  • Nó chỉ là quy ước (void)x; nhưng không phải các phôi khác sẽ ngăn chặn cảnh báo. Tất cả các báo cáo đều không có hiệu lực.
  • Sự khác biệt này bằng cách nào đó liên quan đến thực tế là void x; không phải là tuyên bố hợp lệ trong khi short x; là.

Điều nào trong số này nếu có chính xác hơn? Nếu không, thì làm thế nào có thể sự khác biệt trong các cảnh báo trình biên dịch được giải thích?

+2

Nó chỉ là một quy ước giữa các trình biên dịch mà diễn viên này ngăn chặn cảnh báo. Tiêu chuẩn C++ không đề cập đến các cảnh báo cho "tuyên bố không có hiệu lực". –

Trả lời

20

Truyền để trống được sử dụng để chặn cảnh báo trình biên dịch. Các Standard nói trong §5.2.9/4 cho biết,

bất cứ biểu thức có thể được chuyển đổi một cách rõ ràng để gõ “cv hiệu lực.” Giá trị biểu hiện được loại bỏ.

8

Tuyên bố này:

(void)x; 

Says "Bỏ qua giá trị của x." Không có loại nào như void - đó là sự vắng mặt của một loại. Vì vậy, nó rất khác với điều này:

(int)x; 

Có nội dung "Xử lý x như thể nó là số nguyên". Khi số nguyên kết quả bị bỏ qua, bạn sẽ nhận được một cảnh báo (nếu nó được kích hoạt).

Khi bạn bỏ qua một cái gì đó không có gì, nó không được coi là một vấn đề của GCC - và với lý do chính đáng, kể từ khi đúc thành void là một cách thành ngữ để bỏ qua một biến rõ ràng trong C và C++.

+0

Tôi không bao giờ nghĩ về nó như thế nhưng tôi hơi bối rối, bạn có nghĩ rằng bạn có thể đưa ra một ví dụ để làm rõ khái niệm đúc một biến thành 'void'? – Sacert

+4

Tôi khá chắc chắn có "một loại như" void ". Xem [basic.types]. –

+0

@Sacert: '(void) x' đang truyền một biến để vô hiệu. Bạn tự nói với chính mình. Nhưng một khi bạn đã làm điều đó, bạn không thể làm gì hơn với nó, bởi vì một biểu thức void không có giá trị. –

4

Tiêu chuẩn không bắt buộc phải tạo cảnh báo ("chẩn đoán" theo chuẩn) cho các biến cục bộ hoặc tham số hàm không sử dụng. Tương tự như vậy, nó không ủy quyền làm thế nào một cảnh báo như vậy có thể bị chặn. Việc đúc biểu thức biến thành void để chặn cảnh báo này đã trở thành thành ngữ trong cộng đồng C và sau đó thay vì kết quả không được sử dụng theo bất kỳ cách nào (ngoài ví dụ: (int)x), vì vậy không chắc mã tương ứng bị thiếu. Ví dụ:

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

Cá nhân, tôi thấy ước này quá mơ hồ vẫn còn, đó là lý do tôi thích sử dụng một hàm template:

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

Cách thành ngữ để bỏ qua các tham số hàm được, tuy nhiên, để bỏ qua tên của họ (như đã thấy ở trên).Việc sử dụng thường xuyên mà tôi có cho chức năng này là khi tôi cần để có thể đặt tên cho một tham số chức năng trong mã được biên dịch có điều kiện như là assert. Tôi thấy ví dụ sau đây dễ đọc hơn việc sử dụng #ifdef NDEBUG:

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

Vì C++ 17 bạn có thể sử dụng thuộc tính '[[may_unused]]' thay vì tất cả những cách "sáng tạo" này để bỏ qua một tham số. – Ruslan

Các vấn đề liên quan