2013-08-16 28 views
12

Trong khi gỡ lỗi một số mã của chúng tôi (C++) Tôi thấy điều này:lạ reinterpret_cast (dấu phẩy tách ra biểu thức)

inline std::string BufferToStr(
    const unsigned char* buffer, 
    int index, 
    size_t length) 
{ 
    std::string retValue(reinterpret_cast<const char*>(&buffer[index], length)); 
    return retValue; 
} 

Vấn đề với mã này (nhìn ra thiếu con trỏ và dài chuỗi kiểm tra) là đóng cửa dấu ngoặc đơn của số reinterpret_cast đã được đặt sau length khi cần sau &buffer[index]. Lúc đầu, tôi nghĩ rằng đây là một vấn đề với trình biên dịch (sử dụng VS2013) nhưng sau khi biên dịch thành công bằng cách sử dụng cả hai VS2012 và gcc 4.6.3, tôi đã đi đến kết luận rằng đây là vì lý do nào đó được cho phép. Mã sẽ không chạy trên Windows hoặc Linux vì tham số chiều dài được sử dụng làm con trỏ.

Vì vậy, câu hỏi của tôi là tại sao tính toán này? Nhìn vào tài liệu của reinterpret_cast Tôi không thể tìm thấy bất kỳ tài liệu nào về nó nói rằng bạn có thể chuyển danh sách giá trị được phân cách bằng dấu phẩy cho nó và nó sẽ làm gì với nó.

+0

Tại sao nó không biên dịch? Bạn đang yêu cầu trình biên dịch tạo một 'size_t' thành' const char * 'và nó thực hiện điều đó. Nó không cần phải có ý nghĩa để được cho phép. – Damon

+0

Lưu ý rằng việc bật cảnh báo sẽ đưa ra một dấu hiệu mạnh mẽ về những gì đang diễn ra như tôi đã trình bày trong câu trả lời của tôi với ví dụ sử dụng 'gcc'. –

Trả lời

12

reinterpret_cast chấp nhận expression. Những gì bạn có trong dấu ngoặc đơn là một biểu thức - "," operator với hai biểu thức con, sẽ đánh giá kết quả của biểu thức phụ cuối cùng.

+0

Toán tử dấu phẩy là câu trả lời. Tôi đã quên mất điều đó. Xem nhanh phần 5.18 trong cuốn "Cẩm nang tham khảo C++ đã được chú giải" của Stroustrup đã giải thích rõ ràng. Cảm ơn câu trả lời nhanh của bạn. – william

4

Đó là comma operator. Nó đánh giá các biểu thức trên cả hai mặt của dấu phẩy, nhưng trả lại kết quả của biểu thức bên phải.

Lý do trình biên dịch không phàn nàn là vì bạn đơn giản cho trình biên dịch biết kết quả của biểu thức (loại size_t) nên được coi là biểu thức const char*. Đó là những gì reinterpret_cast làm, nó cho phép đúc hầu như bất kỳ loại nào đến gần như bất kỳ loại nào khác, không có vấn đề làm thế nào ngu ngốc nó có thể được.

3
reinterpret_cast <new_type> (expression)   

reinterpret_cast chấp nhận một expression. Ở đây bạn có một toán tử dấu phẩy, người đánh giá các biểu thức trên cả hai mặt và trả về biểu thức righ-hand.

Thực tế, biểu thức (&buffer[index], length) tương đương với (length) tại đây.

Chỉ cần xem: http://msdn.microsoft.com/en-us/library/zs06xbxh.aspx hoặc http://en.wikipedia.org/wiki/Comma_operator để giải thích toán tử dấu phẩy.

Để kết luận, tại đây bạn đang yêu cầu trình biên dịch của mình tạo một size_t (kết quả của biểu thức) thành const char* và có thể thực hiện điều đó.

7

Đó là do comma operator bằng c/C++. Mã (một biểu thức):

(&buffer[index], length) 

tương đương với (& đệm [index] mất không có tác dụng):

(length)

do đó, mã của bạn là tương đương với:

inline std::string BufferToStr(const unsigned char* buffer, int index, size_t length) 
{ 
    std::string retValue(reinterpret_cast<const char*>(length)); 
    return retValue; 
} 
2

Đây là một trong những lý do tại sao điều quan trọng là phải bật cảnh báo, có thể nó sẽ giúp bạn tự giải quyết vấn đề này.Sử dụng gcc và chạy với -Wall, đây là cảnh báo tôi nhận được:

warning: left operand of comma operator has no effect [-Wunused-value] 
std::string retValue(reinterpret_cast<const char*>(&buffer[index], length)); 
                   ^

Bạn có thể xem live example.

Cảnh báo cho chúng ta biết rằng chúng ta đang sử dụng comma operator lúc đầu này có thể là một chút khó hiểu nhưng reinterpret_cast không phải là một lời gọi hàm trong đó điều này sẽ không làm việc mà không sử dụng dấu ngoặc đơn như chúng ta có thể thấy in this contrived example, nhưng một biểu và trong phần 5.2Postfix biểu thức của tiêu chuẩn dự thảo C++ các ngữ pháp cho postfix thể hiện chứa:

postfix-expression: 
    ... 
    reinterpret_cast < type-id > (expression) 
    ... 

và chúng ta có thể sử dụng một expression trong đối số quá 0.123.hoàn toàn hợp lệ.

+1

Tôi hoàn toàn đồng ý với bạn về điều này và tôi thường có mức cảnh báo tại -Wall. Trong dự án này nó đã được thiết lập trên cấp 3 trong Visual Studio và không tạo ra bất kỳ cảnh báo nào, tôi đã thay đổi nó thành -Wall nhưng nó vẫn không cảnh báo về điều này. Vì vậy, có vẻ như gcc, ít nhất trong trường hợp này, tốt hơn là báo cáo cảnh báo. – william

+0

@william Tôi đã sử dụng ví dụ 'gcc' vì bạn đã đề cập đến bạn đã thử' gcc 4.6.3' và 'gcc' quay lại ít nhất là '4.4.4' cũng cảnh báo,' clang' cũng đưa ra một cảnh báo tốt. –

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