2015-06-21 32 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