Какова внутренняя структура объекта класса CString (EDIT: MFC)? - PullRequest
0 голосов
/ 25 февраля 2012

Мне нужно strncpy() (эффективно) из объекта CString ( Edit: MFC) в строковую переменную C.Хорошо известно, что strncpy() иногда не удается (в зависимости от длины источника ** EDIT и длины, указанной в вызове) правильно завершить строку dest C.Чтобы избежать этого зла, я собираюсь сохранить NUL-символ внутри исходного объекта CString, а затем strcpy() или memmove() этого парня.

Это разумный способ сделать это?Если так, что я должен манипулировать внутри объекта CString?Если нет, то какова альтернатива, которая будет гарантировать правильно завершенную строку C назначения?

Ответы [ 7 ]

1 голос
/ 25 февраля 2012

CString оканчивается на NULL, поэтому, если ваш текст верен (внутри нет символов NULL), копирование должно быть безопасным. Вы можете написать:

char szStr[256];
strncpy(szStr, (LPCSTR) String, 3);
szStr[3]='\0'; /// b-cos no null-character is implicitly appended to the end of destination

если вы храните null где-нибудь внутри объекта CString, вы, вероятно, создадите себе больше проблем, CString хранит его длину внутри себя.

1 голос
/ 25 февраля 2012

Если вы не компилируете с включенным _UNICODE, тогда вы можете легко получить const char * из CString.Просто приведите его к LPCTSTR:

CString myString("stuff");
const char *byteString = (LPCTSTR)myString;

Это гарантированно завершится NULL.

Если у вас есть , построенный с _UNICODE, тогда CString является строкой в ​​кодировке UTF-16.С этим ничего не поделаешь.

Если вам нужно скопировать данные из CString, это очень просто, даже используя код в стиле C.Просто убедитесь, что вы выделяете достаточно памяти и копируете нужную длину:

CString myString("stuff");
char *outString = (char*)malloc(myString.Length() + 1);
strncpy(outString, (LPCTSTR)myString, myString.Length());
1 голос
/ 25 февраля 2012

Одним из альтернативных способов было бы сначала обнулить строку, а затем привести ее или memcpy из CString.

1 голос
/ 25 февраля 2012

strncpy() только «не может» завершить строку назначения нулем, если длина исходной строки превышает указанное вами ограничение длины. Вы можете убедиться, что назначение завершено нулем, установив для своего последнего символа значение null. Например:

#define DEST_STR_LEN 10

char dest_str[DEST_STR_LEN + 1];  // +1 for the null
strncpy(dest_str, src_str, DEST_STR_LEN);
dest_str[DEST_STR_LEN] = '\0';

Если src_str длиннее DEST_STR_LEN символов, dest_str будет правильно завершенной строкой DEST_STR_LEN символов. Если src_str короче этого значения, strncpy() поместит нулевой терминатор где-то в пределах dest_str, поэтому нулевое значение в самом конце неактуально и безвредно.

1 голос
/ 25 февраля 2012

Надеюсь, они не изменились с тех пор, как я их использовал: это было много лет назад:)

Они использовали интересную «хитрость» для обработки refcount и очень быстрое и эффективное автоматическое преобразование в char *: т.е. указатель на LPCSTR, но некоторый резервный байт зарезервирован для сохранения состояния реализации.

Таким образом, структура может использоваться с более старым Windows API (LPCSTR без издержек). Я нашел в то время идею интересной!

Конечно, ключ - это доступность распределителей: они просто смещают указатель при неправильном использовании / освобождении.

Я помню, что был запрос буфера для (например) изменения доступных данных: GetBuffer (0), затем ReleaseBuffer ().

НТН

1 голос
/ 25 февраля 2012

CSimpleStringT :: GetString дает указатель на строку с нулевым символом в конце. Используйте это в качестве соура для strncpy. Поскольку это C ++, вы должны использовать только строки в стиле C при взаимодействии с устаревшими API. Вместо этого используйте std::string.

0 голосов
/ 26 февраля 2012

Другое альтернативное решение скорее включало бы поддержку ЦП или компилятора, так как это гораздо лучший подход - просто убедитесь, что при копировании памяти в «безопасном» режиме в любое время после каждой атомарной операции в конце добавляется ноль, поэтому когда весь цикл завершается неудачно, строка назначения все равно будет завершена, без необходимости полностью обнулять ее перед копированием. Также может быть поддержка быстрого нуля - просто отметьте начало и конец обнуленной области, и она мгновенно очищается в ОЗУ, это намного упростит процесс.

...