Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.53/19: Рейтинг темы: голосов - 19, средняя оценка - 4.53
63 / 64 / 11
Регистрация: 27.02.2013
Сообщений: 1,116
1

Сконвертить PCHAR в AnsiString

18.07.2014, 22:45. Показов 3860. Ответов 23
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
как сконвертить PCHAR в AnsiString? или просто присвоить переменной типа AnsiString переменную типа PCHAR (может у этого класса есть какой то метод для этого...)
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
18.07.2014, 22:45
Ответы с готовыми решениями:

Как перевести текст из AnsiString (в формате UTF8) в AnsiString формата Windows-1251?
Поиск по форуму не решил текущую проблему: 1. Есть текст в формате UTF-8 в величине: AnsiString...

Как сконвертить png в ico?
Как сконвертить png в ico?

Где/как лучше сконвертить траф?
Доброго дня, форумчане. Есть сайт с сочинениями по литературе, траф чуть больше тысячи уников в...

Как сконвертить формат даты VBA в С#?
Как сконвертить формат даты VBA в С#? Что надо написать в ExpirationDate, чтобы все заработало ...

23
Почетный модератор
Эксперт С++
5850 / 2861 / 392
Регистрация: 01.11.2011
Сообщений: 6,907
29.07.2014, 15:23 21
Author24 — интернет-сервис помощи студентам
А вообще вопрос интересный.
Цитата Сообщение от GetHelp Посмотреть сообщение
теряется последний символ
Не последний, а последние, не кратные двум:
Входные символы Полученная строка
123-567-91 123-567-91
123-567-9 123-567-
123-567- 123-567-
123-567 вообще бардак
И вообще там очень интересное поведение. Если меньше восьми символов, то бардак полнейший.

В справке даже описан случай:
C++
1
2
     char* cp = Edit1->Text.c_str();
     char* cp2 = strtok( cp, " \t\n" ); // cp may no longer be valid
И собственно указано как в таком случае поступать:
C++
1
2
     char* cp = new char[ Edit1->Text.Length() + 1 ];
     strcpy( cp, Edit1->Text.c_str() );
Все прекрасно работает.

Но все же вертаясь к вопросу GetHelp.
Вот такой код:
C++
1
2
3
4
5
6
7
8
void __fastcall TForm1::Button2Click(TObject *Sender)
{
char *str = Edit1->Text.c_str(); // Вариант тс
Memo1->Clear();
for( int i=0; i<Edit1->Text.Length() + 1; i++ )
  Memo1->Lines->Add( (int)str[i] );
Edit2->Text = str;
}
Дает вот такой результат:
Сконвертить PCHAR в AnsiString


Вопрос: почему?
0
4043 / 2332 / 292
Регистрация: 03.02.2011
Сообщений: 5,066
Записей в блоге: 10
29.07.2014, 16:19 22
Вот поэтому:

C++
1
2
3
typedef System::UnicodeString TCaption;
//...
__property TCaption Text = {read=GetText, write=SetText};
Edit1->Text - копия класса UnicodeString или AnsiString, хранящегося в эдите. То есть, неявно созданный временный объект в стэке.
Как бы, класс этот устроен так, что внутренние указатели на данные у оригинала и немодифицированной копии одинаковые для экономии памяти. Но тут может быть заковырка - чтобы обеспечить закрытость внутренних данных эдита, метод геттера для свойства Text может как-то создавать полностью независимую копию и возвращать уже ее. Тогда получаем уже вовсе временный объект и любые указатели на его части могут оказаться невалидными в любой момент. Как-то так...
0
Почетный модератор
Эксперт С++
5850 / 2861 / 392
Регистрация: 01.11.2011
Сообщений: 6,907
30.07.2014, 15:44 23
Ну это-то понятно - надо было мне так сказать и продолжить тупить.
Но заместо этого я убил кучу времени, чтобы понять о чем говорит славный BRcr во фразе
Цитата Сообщение от BRcr Посмотреть сообщение
у оригинала и немодифицированной копии
, когда вроде бы мы ничего и не копируем.

Да. Все это так: при попытке изменить содержимое строки сеттером, произойдет копирование измененного значения в новую область памяти. При присваивании же нескольким строкам значения одной из них, физически память не будет расходоваться на новые копии, так как они будут просто ссылаться на эту строку, просто будет увеличиваться счетчик ссылок у данной конкретной записи.

Как это работает

У класса, в частности AnsiString, данные, непосредственна строка, расположены сразу после структуры, описывающей эту строку:
C++
1
2
3
4
5
6
7
8
9
struct StrRec {
#ifdef _WIN64
  int _Padding;
#endif /* _WIN64 */
  unsigned short codePage;
  unsigned short elemSize;
  int refCnt;
  int length;
};
, где refCnt это и есть счетчик ссылок, показывающий сколько еще строк используют точно такую же последовательность символов.
Зная его устройство легко посчитать смещение, которое необходимо вычесть из адреса первого элемента строки, чтобы узнать значение счетчика ссылок:
C++
1
2
const unsigned Shift = sizeof( int ) + // StrRec.refCnt
                       sizeof( int );  // StrRec.length
Вообще. Класс AnsiString устроен так, что его создающиеся объекты могут и не создаваться полными объектами, а лишь определяться как указатели. И это как раз зависит от значения счетчика ссылок.
Всего существует три случая:
Как создается экземпляр Что из себя представляет Значение счетчика
Создается пустая строка (не содержит символов). Нулевой указатель Мусор
Создается строка, инициализирующаяся другим экземпляром Указатель на инициализирующий объект Количество таких объектов
Создается строка, инициализирующаяся произвольной строкой (константой, массивом символов), или изменяется существующая строка, со счетчиком ссылок, большим единицы Полноценный объект Единица

Собственно коды, демонстрирующие выше сказанное:

Для первого случая:
C++
1
2
3
4
AnsiString AStr; // Хотя при AStr = "" все же что-то создает
char *p = AStr.c_str() - Shift;
int *ip = reinterpret_cast<int*>( p );
ShowMessage( *ip );
В многих источниках пишут, что там содержится нуль или даже минус единица, объясняя последнее тем, что переменная счетчика ссылок знаковая, но из наблюдений это все не так. Хотя я тут до конца не разобрался.

Для второго случая:
C++
1
2
3
4
5
6
AnsiString AStr = "hell";
AnsiString AStr2 = AStr;
AnsiString AStr3 ( AStr ); // Без разницы
char *p = AStr.c_str() - Shift;
int *ip = reinterpret_cast<int*>( p );
ShowMessage( *ip ); // 3

Для третьего случая:
C++
1
2
3
4
5
6
7
char *ch = "hell";
AnsiString AStr = ch; // Хоть сразу AStr = "hell";
AnsiString AStr2 = ch;
AnsiString AStr3 = ch;
char *p = AStr.c_str() - Shift;
int *ip = reinterpret_cast<int*>( p );
ShowMessage( *ip ); // 1



Теперь про изменение самого значения, общего для всех. Не даром я вначале сообщения выделил про изменение строки через сеттер класса. При обращении через него все копируется, все хорошо. Но если врукопашную добраться до этой самой искомой строки и набедокурить в ней, то и у всех зависимых строк так же все естественно поменяется:
C++
1
2
3
4
5
6
7
8
AnsiString AStr = "hell";
AnsiString AStr2 = AStr;
AnsiString AStr3( AStr );
 
char *ch = (char*)AStr3.data(); // Изменяем у AStr3...
ch[AStr3.Length()/2] = '6'; // (Куда-нибудь в серединку)
 
Memo1->Lines->Add( AStr ); // ...а выводим AStr
При обращении через геттер класса вообще ничего не изменяется и соответственно никуда не копируется.

Возвращаясь к нашим баранам:
C++
1
2
3
4
5
6
7
8
AnsiString AStr = "hell";
AnsiString AStr2 = AStr;
AnsiString AStr3 = AStr;
Edit1->Text = AStr;        // До
Edit2->Text = AStr;        //  фонаря
char *p = AStr.c_str() - AShift;
int *ip = reinterpret_cast<int*>( p );
ShowMessage( *ip ); // Все равно будет 3
И соответственно наоборот:
C++
1
2
3
4
5
6
7
Edit1->Text = "hell";
Edit2->Text = "hell";
AnsiString AStr = Edit1->Text;
AnsiString AStr2 = Edit1->Text;
char *p = AStr.c_str() - Shift;
int *ip = reinterpret_cast<int*>( p );
ShowMessage( *ip ); // Будет 1
Следовательно это тут вообще не при делах. Я думаю TEdit не просто инкапсулирует в себе строку, а что-то тут интереснее.
Из UniqueString тут тоже не выстрелить. Да и не имеет смысла это, как видно выше.
Следовательно мой вопрос остается в силе:
C++
1
2
3
4
5
6
char *str = (char*)Edit1->Text.data(); // Вариант тс
Memo1->Clear();
for( int i=0; i<Edit1->Text.Length() + 1; i++ )
  //Memo1->Lines->Add( (int)str[i] ); // Не работает
  Memo1->Lines->Add( (int)((char*)Edit1->Text.data())[i] ); // Работает
Edit2->Text = str;
Почему не работает?
0
4043 / 2332 / 292
Регистрация: 03.02.2011
Сообщений: 5,066
Записей в блоге: 10
30.07.2014, 21:27 24
Обстоятельно. Чтоб у меня стока времени было...

Однако, на вопрос дать ответ пока затрудняюсь - не смог воспроизвести ошибку.
C++
1
2
3
4
5
6
7
8
    TCHAR * str = ( TCHAR * )edit_in->Text.data( );
    memo_out->Clear( );
    for ( int i = 0; i < edit_in->Text.Length( ) + 1; i++ )
    {
        memo_out->Lines->Add( ( int )str[ i ] ); // У меня отработало
        // memo_out->Lines->Add( ( int )( ( TCHAR * )edit_in->Text.data( ) )[ i ] ); // Работает
    }
    edit_out->Text = str;
Название: Снимок.PNG
Просмотров: 50

Размер: 24.3 Кб

Попробую еще перехватчики на конструкторы копирования поставить, может, нам String сам расскажет, что с ним в эдите делают?..
0
30.07.2014, 21:27
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
30.07.2014, 21:27
Помогаю со студенческими работами здесь

PCHAR в String
Помогите начинающему программисту что здесь не так? И правильно ли я проверяю существование папки?...

Pchar из dll
в общем, требуется написать UDF под интербазу, катаем dll library UDFStr2; // uses // ...

Преобразование в Pchar
Как преобразовать число в тип PChar?

Работа с Pchar
Добрый день! У меня есть задача. Hанее почти не работал с PChar. Помогите разобраться. В длл есть...

Pchar и освобождение памяти
Здравствуйте. Написал парсинг страницы сайта. Запрос страницы идёт из основной программы, после...

Небезопасное использование PChar
В программе использую функцию CreateFile. Первый параметр - имя устройства. Его тип PAnsiChar. Если...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
24
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru