2015-06-21 111 views
3

我試圖移植我的代碼從使用MFC的CStringstd::string Microsoft Windows平臺。我對某件事很好奇。在下面的例子中說:如何從std :: string獲得可寫的C緩衝區?

CString MakeLowerString(LPCTSTR pStr) 
{ 
    CString strLower = pStr ? pStr : L""; 
    CharLower(strLower.GetBuffer());  //Use WinAPI 
    strLower.ReleaseBuffer(); 

    return strLower; 
} 

我使用strLower。 GetBuffer()獲取一個可寫入的緩衝區以傳遞給CharLower API。但我在std::string中沒有看到類似的方法。

我錯過了什麼嗎?如果是這樣,你將如何使用std::string覆蓋上面的方法?

+1

你*不*。如果你需要修改字符串,你可以修改字符串。如果您將字符串傳遞給採用常量字符指針的舊函數,則只需要「C緩衝區」。 –

+1

@JoachimPileborg:好的,假設'CharLower' API不是'CharLower',而是一些任意的API,它會修改我需要從'std :: string'獲取的輸入緩衝區。我會怎麼做?這就是我要問的。 – c00000fd

+0

我告訴你,你不需要*原始緩衝區,你需要的所有東西都已經在字符串類或標準庫中。看看例如http://en.cppreference.com/w/cpp並在那裏瀏覽一段時間。 –

回答

2

的接受的方式,以小寫字母a std::string是:

#include <algorithm> 
#include <string> 

std::string data = "Abc"; 
std::transform(data.begin(), data.end(), data.begin(), ::tolower); 

你真的不能得到解決,通過每個字符迭代。原始的Windows API調用將在內部執行相同的字符迭代。

如果你需要得到toLower()比標準的「C」語言環境以外的環境中,你可以改用:

std::string str = "Locale-specific string"; 
std::locale loc("en_US.UTF8"); // desired locale goes here 
const ctype<char>& ct = use_facet<ctype<char> >(loc); 
std::transform(str.begin(), str.end(), str.begin(), std::bind1st(std::mem_fun(&ctype<char>::tolower), &ct)); 

直接回答你的問題,並減去任何情況下,你可以調用str.c_str()得到來自std::stringconst char *(LPCSTR)。您不能直接將std::string轉換爲char *(LPTSTR);這是通過設計來破壞使用std::string的一些動機。

+1

請不要脫軌。我並沒有要求轉換成小寫。這只是我快速整合的一個例子。我問的是從std :: string獲得一個可寫的緩衝區。 – c00000fd

+0

@ c00000fd我相信,這與您問題中的代碼一樣多。字符串類和標準庫有你需要的一切。 –

+0

是的,我可以得到'const char *',但是如何從中得到'char *'?我是否需要自己分配它並在那裏複製我的字符串。這不是浪費CPU週期嗎? – c00000fd

1

根據您的要求,您可以使用以下的一種或多種:

  1. std::string::operator[]()。此函數返回給定索引處的字符,不進行邊界檢查。

  2. std::string::at()。此函數返回給定索引處的字符並進行邊界檢查。

  3. std::string::data()。該函數返回指向原始數據的const指針。

  4. std::string::c_str()。該函數返回值相同std::string::data()

+1

謝謝。是的,我發現我可以得到一個'const'指向字符串的指針,但是我無法修改它,對嗎?否則它不會是一個'const',會不會? – c00000fd

+0

沒錯,你不能通過'data()'和'c_str()'返回的指針來修改字符串。 –

+1

嗯。有趣。人們告訴我,'std :: string'比MFC的'CString'好得多。我不確定在不能做最簡單的操作後是否屬實。 – c00000fd

2
void GetString(char * s, size_t capacity) 
{ 
    if (nullptr != s && capacity > 5) 
    { 
     strcpy_s(s,capacity, "Hello"); 
    } 
} 

void FooBar() 
{ 
    std::string ss; 
    ss.resize(6); 
    GetString(&ss[0], ss.size()); 
    std::cout << "The message is:" << ss.c_str() << std::endl; 
} 

正如你所看到的,你可以使用「老派C-指針」既餵養字符串遺贈功能以及使用它作爲一個OUT參數。當然,你需要確保,字符串中有足夠的容量來工作等。

+0

它保證是可能的,還是它是你的標準庫實現的怪癖? – immibis

+0

您似乎可以互換使用「容量」和「大小」,因爲在C++庫中,「容量」和「大小」意味着兩個不同的東西。 –

+0

是的,我可以寫更好的容量/尺寸的東西。從函數GetString()的角度來看,調用者端的std :: string的大小就是容量。 ;) – BitTickler

4

在我的新工作中,我們不使用MFC--但幸運的是std lib和C++ 11--所以我已經遇到與c00000fd相同的問題。感謝BitTickler的回答,我提出了通過&s[0]或其他方法使用字符串內部緩衝區來實現Win32-API的想法。 &s.front()趕上。

使用收縮內部串緩衝器

假定有應由一個Win32-API函數成爲縮短的字符串Win32的API函數 - 例如::PathRemoveFileSpec(path) - 您可以按照下列方法:

std::string path(R("?(C:\TESTING\toBeCutOff)?")); 
::PathRemoveFileSpec(&path.front()); // Using the Win32-API 
             // and the the string's internal buffer 
path.resize(strlen(path.data())); // adjust the string's length 
             // to the first \0 character 
path.shrink_to_fit();     // optional to adjust the string's 
             // capacity - useful if you 
             // do not plan to modify the string again 

Unicode版本:

std::wstring path(LR("?(C:\TESTING\toBeCutOff)?")); 
::PathRemoveFileSpec(&path.front()); // Using the Win32-API 
             // and the the string's internal buffer 
path.resize(wcslen(path.data())); // adjust the string's length 
             // to the first \0 character 
path.shrink_to_fit();     // optional to adjust the string's 
             // capacity - useful if you 
             // do not plan to modify the string again 

使用Win32的API函數,延伸內部字符串緩衝區

假設你有一個字符串它們將由Win32-API函數擴展或填充 - 例如::GetModuleFileName(NULL, path, cPath)檢索您的可執行文件的路徑 - 你可以參照下面的方法:

std::string path; 
path.resize(MAX_PATH);     // adjust the internal buffer's size 
             // to the expected (max) size of the 
             // output-buffer of the Win32-API function 
::GetModuleFileName(NULL, &path.front(), static_cast<DWORD>(path.size())); 
             // Using the Win32-API 
             // and the the string's internal buffer 
path.resize(strlen(path.data())); // adjust the string's length 
             // to the first \0 character 
path.shrink_to_fit();     // optional to adjust the string's 
             // capacity - useful if you 
             // do not plan to modify the string again 

Unicode版本:

std::wstring path; 
path.resize(MAX_PATH);     // adjust the internal buffer's size 
             // to the expected (max) size of the 
             // output-buffer of the Win32-API function 
::GetModuleFileName(NULL, &path.front(), static_cast<DWORD>(path.size())); 
             // Using the Win32-API 
             // and the the string's internal buffer 
path.resize(wcslen(path.data())); // adjust the string's length 
             // to the first \0 character 
path.shrink_to_fit();     // optional to adjust the string's 
             // capacity - useful if you 
             // do not plan to modify the string again 

當你終於縮小到適合的字符串,那麼你只需要一個更多的代碼行當擴展字符串的內部緩衝區與MFC替代方法相比時,縮小字符串時它具有幾乎相同的開銷。

在對比的是CString方法的std::string方法的優點是,你不必聲明一個額外的C字符串指針變量,你只是與官方std::string方法的工作原理和strlen/wcslen功能。 上面顯示的我的方法只適用於收到的Win32-API緩衝區爲空終止的變體,但對於Win32-API返回未終止字符串的特殊情況,則 - 類似於CString::ReleaseBuffer方法 - 必須明確知道並指定新的字符串/緩衝區長度path.resize(newLength) - 就像path.ReleaseBuffer(newLength)替代CString