2011-07-07 23 views
11
class MyString 
{ 
public: 
    MyString(const std::wstring& s2) 
    { 
     s = s2; 
    } 

    operator LPCWSTR() const 
    { 
     return s.c_str(); 
    } 
private: 
    std::wstring s; 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    MyString s = L"MyString"; 
    CStringW cstring = L"CString"; 
    wprintf(L"%s\n", (LPCWSTR)cstring); // Okay. Becase it has an operator LPCWSTR() 
    wprintf(L"%s\n", cstring); // Okay, fine. But how?   
    wprintf(L"%s\n", (LPCWSTR)s); // Okay. fine. 
    wprintf(L"%s\n", s); // Doesn't work. Why? It prints gabage string like "?." 
    return 0; 
} 

Làm cách nào để CString có thể được chuyển tới chuỗi định dạng% s?Làm cách nào để CString có thể được chuyển tới chuỗi định dạng% s?

Bằng cách này, MSDN says (đó là lạ)

Để sử dụng một đối tượng CString trong một chức năng lập luận biến
Rõ ràng cast CString để một chuỗi LPCTSTR, như ở đây:

CString kindOfFruit = "bananas"; 
int  howmany = 25; 
printf("You have %d %s\n", howmany, (LPCTSTR)kindOfFruit); 
+2

"Không hoạt động" nghĩa là gì? Không biên dịch, không hiển thị kết quả mong đợi ...? – MikMik

+2

Điều này hoàn toàn không liên quan gì đến C. – Puppy

+0

@MikMik: Nó hiển thị chuỗi gabage như ** "?." ** – Benjamin

Trả lời

9

CString được thiết kế đặc biệt sao cho nó chỉ chứa một con trỏ trỏ đến dữ liệu chuỗi trong một lớp đệm. Khi được chuyển bởi giá trị tới printf, nó sẽ được coi là một con trỏ khi nhìn thấy "% s" trong chuỗi định dạng.

Ban đầu nó chỉ xảy ra để làm việc với printf một cách tình cờ, nhưng điều này sau đó đã được giữ như là một phần của giao diện lớp.


Bài đăng này dựa trên tài liệu MS từ lâu kể từ khi nghỉ hưu, vì vậy tôi không thể liên kết với lời hứa rằng họ sẽ tiếp tục thực hiện công việc này.

Tuy nhiên, trước khi bổ sung thêm downvotes cũng xin vui lòng đọc bài viết trên blog này từ một người nào đó chia sẻ kiến ​​thức cũ của tôi:

Big Brother helps you

+2

Tôi vẫn không biết cách in bằng cách sử dụng 'printf'. Bạn có thể cho thấy một ví dụ? –

6
wprintf(L"%s\n", (LPCWSTR)cstring); // Okay. It's been cast to a const wchar_t*. 
    wprintf(L"%s\n", cstring); // UNDEFINED BEHAVIOUR 
    wprintf(L"%s\n", (LPCWSTR)s); // Okay, it's a const wchar_t*. 
    wprintf(L"%s\n", s); // UNDEFINED BEHAVIOUR 

Chỉ điều bạn có thể chuyển đến func này tion cho %sconst wchar_t*. Bất cứ điều gì khác là hành vi không xác định. Việc vượt qua CString chỉ xảy ra để hoạt động.

Có lý do là iostream được phát triển bằng C++ và đó là vì các hàm đối số biến này không an toàn khủng khiếp và không bao giờ được sử dụng. Ồ, và CString cũng là một tội lỗi quá nhiều vì nhiều lý do, hãy dính vào std::wstringcout/wcout ở bất cứ nơi nào bạn có thể.

+3

Hành vi không xác định cho CString thực sự là hành vi thực hiện cụ thể. Microsoft hỗ trợ việc sử dụng này. –

+2

@BoP đó là hành vi không xác định trong C++, bởi vì nó là hành vi không xác định trong tài liệu thư viện chuẩn 'printf' của C. Đó là microsoft mang lại cho nó một ý nghĩa (tôi vẫn chưa thấy một tài liệu chính thức nào, mặc dù) là tốt, nhưng mã vẫn không di động. –

+1

@Johannes - Chắc chắn là vậy, nhưng câu hỏi là tại sao nó vẫn hoạt động cho CString. –

2

Nói chung đó là hành vi không xác định. Theo this article Visual C++ chỉ yêu cầu chuyển đổi từ CString thành loại POD để trang trải cho bạn - đó là việc triển khai cho phép hành vi không xác định.

3

CString có một con trỏ là thành viên đầu tiên:

class CStringA 
{ 
     char* m_pString; 
}; 

Mặc dù nó không phải là char* (ngay cả đối với ANSI CString), nó là nhiều hơn hoặc ít hơn những điều tương tự. Khi bạn vượt qua đối tượng CString cho bất kỳ printf-family nào của các hàm (bao gồm cả việc triển khai tùy chỉnh của bạn, nếu có), bạn đang truyền đối tượng CString (nằm trên stack). Việc phân tích cú pháp %s khiến nó đọc như thể nó là một con trỏ - đó là một con trỏ hợp lệ trong trường hợp này (dữ liệu ở byte đầu tiên là m_pString).

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