2010-10-08 2 views
2

Как преобразовать std :: string в LPCSTR, сохраняя символы '\ 0'?конвертировать std :: string в LPCSTR с конечным или ведущим ' 0'

Я хочу использовать результат на OPENFILENAME.lpstrFilter, который требует, чтобы фильтр содержал '\ 0' в качестве разделителей.

станд :: string.c_str(), кажется, раздеться и дифферента '\ 0'

Спасибо заранее!

==========================

(Как правильно добавить комментарий к ответам, как в ответ пост в ? форум)

После прочтения ваших комментариев, я пошел на перепроверить этот фрагмент:

std::string filter = "Terrain Configuration (*.tcfg)\0*.tcfg\0\0"; 
const char* f1 = "Terrain Configuration (*.tcfg)\0*.tcfg\0\0"; 
const char* f2 = filter.c_str(); 
for(int i = 0; i < 50; i++) 
{ 
char c1 = *(f1 + i); // works 
char c2 = *(f2 + i); // doesn't work. beyond the first \0, it's garbage. 
} 

я ошибаюсь о том, как работает c_str() или LPCSTR?

+0

См http://msdn.microsoft.com/en-us/library/ ms646839% 28VS.85% 29.aspx: 'lpstrFilter: последняя строка в буфере должна быть прервана двумя символами NULL.'. Вам нужно ** два ** NULL символов в конце, чтобы этот параметр работал правильно; 'c_str()' по дизайну имеет только один. – AshleysBrain

+0

Да, я знаю этот факт. – Jake

ответ

6

C_STR не снимает символы NUL. Вероятно, ошибка связана с тем, как вы строите STD :: string.

+0

c_str не снимает нуль, но будьте осторожны, он возвращает указатель, который по-прежнему принадлежит классу строк, поэтому вы должны обязательно скопировать содержимое. –

+0

Пожалуйста, просмотрите отредактированный вопрос со снимком. Это в том же объеме, не так ли? – Jake

+1

Независимо от того, что Александр указывает, что в вашем фрагменте фильтр std :: string не инициализируется вашим полным вводом, потому что конструктор перестанет читать в первом нуле. В соответствии с приведенным ниже ответом Стива вам нужно использовать 'std :: string filter (« Конфигурация ландшафта (* .tcfg) \ 0 * .tcfg \ 0 \ 0 ", 40);' Я думаю. – Rup

1

Это зависит от дальнейшего жизненного цикла std :: string.

Например, вы можете добавить терминальный ноль вручную:

std::string test("init"); 
test += '\0'; 

Это приводит к тому длина должна быть увеличена на единицу. Или просто создайте еще один экземпляр std :: string с добавленным нулем

2

length()string - это то, что вам нужно использовать для обеспечения включения всех символов при условии, что оно было правильно сконструировано в первую очередь, чтобы включить в себя встроенные символы \0.

Для того LPCSTR действует при cString находится в области видимости:

#include <boost/scoped_array.hpp> 
#include <string> 
#include <algorithm> 

string source("mystring"); 
boost::scoped_array<char> cString(new char[source.length() + 1]); 

std::copy(source.begin(), source.end(), cString.get()); 
cString[source.length()] = 0; 

LPCSTR rawStr = cString.get(); 

Без scoped_array:

#include <string> 
#include <algorithm> 

string source("mystring"); 
LPSTR rawStr = new char[source.length() + 1]; 

std::copy(source.begin(), source.end(), rawStr); 
rawStr[source.length()] = 0; 

// do the work here 

delete[] rawStr; 

EDIT: В вашем filter инициализации, конструктор string включает только данные до первого \0 знак. Это имеет смысл - как иначе он не перестанет копировать данные, когда все, что у него есть, это const char *? Попробуйте это:

const char f3[] = "Terrain Configuration (*.tcfg)\0*.tcfg\0\0"; 
std::string filter(f3, sizeof(f3)); 
+0

hmm ... Я мог бы копировать один символ за раз, но просто надеялся, что есть более быстрый способ. – Jake

+0

@Jake - 'std :: copy' удаляет необходимость в байтовом байтовом контуре. Если вы удалите 'scoped_array' выше, он может быть более понятным, просто новым непосредственно в' rawStr'. См. Править. –

5

Вообще говоря, std :: string обрабатывает встроенные символы '\ 0' правильно.

Однако при взаимодействии с const char * необходимо проявлять особую осторожность.

В этом случае проблема уже происходит во строящейся строки с:

std::string filter = "Terrain Configuration (*.tcfg)\0*.tcfg\0\0"; // wrong 

Здесь вы построить зЬй :: строку из константного символа *. Поскольку конструктор не знает, сколько символов нужно использовать для построения std :: string, он останавливается при первом '\ 0'.

Можно копировать символы, один за другим, самому себе, но есть лучший способ: использовать застройщик, который требует два итератора в массив символов, один с начала и одного с конца:

const char filter_[] = "Terrain Configuration (*.tcfg)\0*.tcfg\0\0"; 
std::string filter(filter_, filter_ + sizeof(filter_)); 

Это выглядит ужасно, но, надеюсь, вы не будете так часто делать это в своем коде.

Update: Или с определениями Бегин наши правила() и конец() шаблоны (как на комментарий Джеймса Kanze в):

const char filter_[] = "Terrain Configuration (*.tcfg)\0*.tcfg\0\0"; 
std::string filter(begin(filter_), end(filter_)); 
+0

Это sizeof (filter_) - 1, если в константе строки уже есть –

+1

К сожалению, не используется для этого интерфейса: Это sizeof (filter_) - 1, если константа строки уже содержит double \ 0. Инициализация массива со строкой константа автоматически добавляет '\ 0'. И, конечно, это использование sizeof будет ломаться, когда char изменен на wchar_t. Лучше было бы использовать обычный шаблон функции begin (filter_), end (filter_), например: \t std :: string (begin (filter_), end (filter_)); –

+0

@James Kanze: Спасибо, что указали на шаблоны begin() и end(), я их еще не знал. – Sjoerd

Смежные вопросы