2014-07-03 21 views
16

Xem xét việc này (nhân tạo) ví dụ:Tại sao ostream in `1` cho một chuỗi được định nghĩa là` volatile char [] `?

#include <cstdio> 
#include <iostream> 

int main() { 
    volatile char test[] = "abc"; 
    std::printf("%s\n", test); 
    std::cout << test << "\n"; 
} 

Biên soạn nó với GCC và chạy cho kết quả như sau:

$ g++ test.cc 
$ ./a.out 
abc 
1 

Như bạn thấy printf in chuỗi chính xác trong khi cout in 1. Tại sao viết thư cho cout sản xuất 1 trong trường hợp này?

+3

'volatile char [N]' matches 'bool' better tha n 'const char *'. Trên thực tế, nó không phù hợp với 'const char *'. – chris

+0

@sharth tuyệt vời bắt, tôi thậm chí không nghĩ để tìm một dup. Họ là đủ gần họ có thể làm cho một hợp nhất tốt. –

Trả lời

14

Các chỉ quá tải phù hợp operator<< là đối với bool, vì vậy mảng được chuyển đổi (thông qua một con trỏ) để bool, cho true từ địa chỉ của nó là không null. Kết quả đầu ra này là 1 trừ khi bạn sử dụng trình xử lý std::boolalpha.

Không thể sử dụng quá tải cho const char * sẽ xuất chuỗi hoặc cho const void * sẽ xuất giá trị con trỏ, vì những chuyển đổi đó sẽ yêu cầu xóa loại vòng loại volatile. Chuyển đổi con trỏ tiềm ẩn có thể thêm vòng loại nhưng không thể xóa chúng.

Để đầu ra chuỗi, bạn phải bỏ đi các vòng loại:

std::cout << const_cast<const char*>(test) << "\n"; 

nhưng hãy cẩn thận rằng đây cho hành vi undefined từ mảng sẽ được truy cập như thể nó là không bị tổn hại.

printf là một chức năng cũ của trường phái Denisdic, không có sự an toàn về loại. Các thông số %s làm cho nó diễn giải các đối số như const char *, bất kể nó thực sự là gì.

+2

Điều này có hợp pháp về mặt kỹ thuật không? Liệu toán tử 'có thể <<' tối ưu hóa trên giả thiết rằng chuỗi không biến động? Ví dụ, nó có thể làm 'strlen (s)' để quyết định dung lượng bộ đệm lớn, sau đó sử dụng 'strcpy' để sao chép vào bộ đệm đó. –

+2

Câu trả lời với các hành vi có hành vi không xác định: C++ 14 [dcl.type.cv] p6 nói "Nếu một nỗ lực được thực hiện để chỉ một đối tượng được xác định với một loại có đủ điều kiện dễ bay hơi thông qua việc sử dụng glvalue với một không loại đủ điều kiện dễ bay hơi, hành vi của chương trình là không xác định. " Nói chung, bạn chỉ có thể tương tác với các mảng dễ bay hơi thông qua các vòng viết tay trên các phần tử. –

+0

@JeffreyYasskin Tôi đã tự hỏi về điều này nhưng 'const_cast' trong trường hợp này mang lại một' prvalue' theo như tôi có thể nói nhưng tôi chưa nghĩ chi tiết. –

5

Các std::basic_ostream::operator<< chỉ có một tình trạng quá tải cho const char* hoặc const void* mà không phù hợp trong trường hợp này vì bạn không thể loại bỏ các dễ bay hơi vòng loại mà không có một dàn diễn viên, điều này được bao phủ trong draft C++ standard phần 4.4chuyển đổi Qualification mà nói:

một prvalue kiểu “con trỏ đến CV1 T” có thể được chuyển đổi sang một prvalue của gõ “con trỏ đến CV2 T” nếu “CV2 T” là hơn cv-có trình độ hơn “CV1 T”.

vì vậy nó được sử dụng phiên bản bool và vì nó không phải là một nullptr kết quả là true.

Nếu bạn xóa biến động vòng loại từ test, điều này sẽ cung cấp kết quả bạn mong đợi. Một số câu trả lời gợi ý sử dụng một số const_cast để loại bỏ các vòng loại dễ bay hơi nhưng đây là hành vi không xác định. Chúng ta có thể nhìn thấy bằng cách vào phần 7.1.6.1Các cv-vòng loại đoạn mà nói:

Nếu một nỗ lực được thực hiện để tham khảo một đối tượng được xác định với một loại biến động có trình độ thông qua việc sử dụng một glvalue với loại không đủ điều kiện bay hơi, hành vi của chương trình không xác định.

const_cast trong trường hợp này mang lại một prvalue nhưng dereferencing con trỏ đó mang lại một giá trị trái mà sẽ gọi hành vi không xác định.

2

trả lời tìm thấy here bởi một lượng tối thiểu của các tìm kiếm web:

Câu trả lời ngắn: cout được giải thích các đối tượng như một bool do volatile vòng loại. Đó là một sự gian lận quá tải đối với toán tử <<.

Câu trả lời dài: Một con trỏ dễ bay hơi không thể chuyển đổi thành con trỏ không bay hơi mà không có đoạn mã rõ ràng, vì vậy không thể sử dụng quá trình tải xuống char* hoặc void* khi nhà điều hành << được gọi. Không có tình trạng quá tải đủ điều kiện dễ bay hơi và kết quả gần nhất là quá tải bool, do đó mảng của bạn được hiểu là giá trị boolean thay vì địa chỉ hoặc chuỗi.

Bạn có thể sửa chữa nó một số cách khác nhau, nhưng một diễn viên rõ ràng có lẽ là những gì bạn muốn: (. Cá nhân tôi sẽ đúc để const char*)

std::cout<< (char*)test <<std::endl; 

0

Đó là volatile vòng loại mà đặt nó vào một số bool, hãy thử thay thế:

std::cout << const_cast<char*>(test) << "\n"; 
+0

Câu trả lời này có hành vi không xác định: C++ 14 [dcl.type.cv] p6 nói "Nếu một nỗ lực được thực hiện để chỉ một đối tượng được định nghĩa với một loại đủ điều kiện dễ bay hơi thông qua việc sử dụng một glvalue với một loại không đủ điều kiện bay hơi, hành vi của chương trình là không xác định." –

+0

@ JeffreyYasskin đoán biến này khá ... 'dễ bay hơi'! ;) –

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