Борис Пахомов Санкт Петербург бхв петербург 2013 удк 004. 4 Ббк 32. 973. 26018. 2 П
Скачать 17.38 Mb.
|
String в ASCII - строку Текст программы показан в листинге 14.1, а результат — на рис. 14.1. Рис 14.1. Результат перевода na tive- строки в managed - строку Глава 14. Преобразование между нерегулируемыми и регулируемыми указателями Листинг 14.1 // 14.1_2011 Нерег в Рег.cpp : main project file. #include "stdafx.h" #include #pragma unmanaged сигнал компилятору, что далее следуют функции, работающие с обычными (native) переменными, которые станут размещаться в неуправляемой куче памяти, за переполнением которой надо следить самому — вовремя освобождать от занимающих ее объектов */ void NativeTakesAString(const char* p) { printf("(native) received '%s'\n", p); } #pragma managed сигнал компилятору, что далее следуют функции, работающие со средой CLR, в которой переменные станут размещаться в управляемой куче (памяти, за переполнением которой не надо следить самому — среда CLR сама позаботится об ее освобождении от занимаемых объектов */ int main() //array { String^ s = gcnew String("sample string"); IntPtr ip = Marshal::StringToHGlobalAnsi(s); этот метод выделяет для s место в неуправляемой куче и указатель на это место передает в структуру IntPtr. Указатель имеет тип void, те. его еще надо настроить на конкретный тип данного const char* str = static_cast /*кастинг указателя настройка его на тип с c помощью оператора static_cast */ Console::WriteLine("(managed) passing string..."); т. к. мы находимся в методе main(), то и вывод идет по WriteLine())*/ NativeTakesAString( str ); вызов метода внутри метода 474 Часть II. Приложения Windows Form Marshal::FreeHGlobal( ip ); этот метод освобождает память, выделенную StringToHGlobalAnsi(s): т. к. это уже неуправляемая куча, то память надо освобождать самому */ Console::ReadLine(); } Пример 2. Перевод строки в строку String Текст программы показан в листинге 14.2, а результат — на рис. 14.2. Рис 14.2. Результат преобразования managed - строки в native - строку Листинг 14.2 // 14.2_2011 Прим 2.cpp : main project file. #include "stdafx.h" #include #include #pragma managed void ManagedStringFunc(char* s) здесь функция получает аргумент { String^ ms = Marshal::PtrToStringAnsi(static_cast IntPtr. Затем этот тип преобразуется оператором static_cast в тип String ^ */ Console::WriteLine("(managed): received '{0}'", ms); } #pragma unmanaged Глава 14. Преобразование между нерегулируемыми и регулируемыми указателями void NativeProvidesAString() это функция, которая вызывает функцию { printf("(native) calling managed func...\n"); ManagedStringFunc("test string"); } #pragma managed int это функция, которая вызывает функцию { NativeProvidesAString(); _getch(); } Пример 3. Преобразование строки String в строку Тип wchar_t — это тип символа по таблице Юникода. Этот тип данного отличается от типа char тем, что символ кодируется двумя байтами, а не одним. Класс String тоже создает строку из Юникод-символов, однако по своему определению относится к типу. Преобразование, которое мы рассматриваем, фактически переводит Юникод-строку из состояния managed в состояние native . А в этом состоянии со строкой уже можно работать, применяя обычный указатель * Юникод-тексты можно вводить в файлы и читать из них соответственно функциями и Текст программы показан в листинге 14.3, а результат — на рис. 14.3. Рис 14.3. Результат преобразования Юникод - строки в native - строку Листинг 14.3 // 14.3_2011 Прим 3.cpp : main project file. #include "stdafx.h" #include #include #include 476 Часть II. Приложения Windows Form using namespace System; using namespace System::Runtime::InteropServices; #pragma unmanaged void NativeTakesAString(const wchar_t* p) { printf("(native) recieved '%S'\n", p); } #pragma managed int main() { String^ s = gcnew String("test string"); pin_ptr /* метод размещает s в управляемой куче и выдает указатель типа _const_Char_ptr на размещенный объект. Этот указатель с помощью оператора [cli::]pin_ptr Здесь cv_qualifier — квалификатор const или квалификатор volatile. Квалификатор volatile показывает, что поле может модифицироваться многочисленными средами, выполняющимися в данный момент, и все изменения данного поля будут присутствовать в этом поле. Указатель типа pin_ptr по умолчанию имеет квалификатор volatile, поэтому в операторе применен квалификатор const, чтобы объект в куче не изменял своего значения, а не только месторасположения это ссылочный тип данного элемент массива или любого другого объекта, которому вы назначаете указатель. Метод PtrToStringChars() как рази выдает такой указатель указатель в управляемой (managed) куче. type — тип initializer'a. В нашем случае это wchar_t var — имя pin_ptr указателя. В нашем случае это str. То есть str — это уже указатель строки String ^ в управляемой куче. */ Console::WriteLine("(managed) passing string to native func..."); вывод сообщения из функции NativeTakesAString( str ); вызов функции, которая выдаст сообщение _getch(); } Глава 14. Преобразование между нерегулируемыми и регулируемыми указателями Здесь применен указатель pin_ptr (указатель от зашкаливания, как определяет его автор. Это внутренний указатель, который предотвращает объект (на который он указывает) от какого-либо перемещения в управляемой куче (памяти, с которой работает режим CLR): значение указателя не изменяется средой CLR. Такое условие необходимо при передаче адреса объекта функции, потому что этот адрес не должен меняться вовремя вызова функции. Пример 4. Преобразование строки в строку String Это преобразование — обратное приведенному в примере 3. Преобразование, которое мы рассматриваем, фактически переводит native Юникод-строку в состояние managed . А в этом состоянии со строкой уже можно работать, применяя managed- указатель ^ . Текст программы показан в листинге 14.4, а результат — на рис. 14.4. Рис 14.4. Результат преобразования wchar_t в String Листинг 14.4 // 14.4_2011 Прим 4.cpp : main project file. // 2008-Marshal wchar_t to Unicod.cpp : main project file. #include "stdafx.h" #include #include #pragma managed void ManagedStringFunc(wchar_t* s) { String^ ms = Marshal::PtrToStringUni((IntPtr)s); /* копирует символы строки s в Юникоде в кучу, преобразовывая их в строку, и выдает указатель на месторасположения строки. 478 Часть II. Приложения Windows Form Аргумент метода по его определению должен иметь тип IntPtr (внутренний указатель, поэтому s преобразуется к этому типу. */ Console::WriteLine("(managed) recieved '{0}'", ms); } #pragma unmanaged void NativeProvidesAString() { printf("(unmanaged) calling managed func...\n"); ManagedStringFunc(L"test string"); } #pragma managed int main() { NativeProvidesAString(); _getch(); } Пример 5. Маршалинг native - структуры В данном примере показана работа с структурой в функции. Текст программы показан в листинге 14.5, а результат — на рис. 14.5. Рис 14.5. Маршалинг структуры Листинг 14.5 // 14.5_2011 Прим 5.cpp : main project file. #include "stdafx.h" #include #include Глава 14. Преобразование между нерегулируемыми и регулируемыми указателями #pragma unmanaged структура struct Location { int x; int y; }; параметры функции — два экземпляра структуры double GetDistance(Location loc1, Location loc2) { printf("[unmanaged] loc1(%d,%d)", loc1.x, loc1.y); printf(" loc2(%d,%d)\n", loc2.x, loc2.y); double h = loc1.x — loc2.x; double v = loc1.y = loc2.y; квадратный корень из h2 + v2: double dist = sqrt( pow(h,2) + pow(v,2) ); return dist; } параметр функции — указатель на структуру void InitLocation(Location* lp) { printf("[unmanaged] Initializing location...\n"); lp->x = 50; lp->y = 50; } #pragma managed работа со структурой в функции int main() { Location loc1; loc1.x = 0; loc1.y = 0; Location loc2; loc2.x = 100; loc2.y = 100; вызов функции в функции double dist = GetDistance(loc1, loc2); Console::WriteLine("[managed] distance = {0}", dist); Location loc3; вызов функции в функции в ее параметре указатель, поэтому берется адрес экземпляра структуры 480 Часть II. Приложения Windows Form InitLocation(&loc3); Console::WriteLine("[managed] x={0} y={1}", loc3.x, loc3.y); Console::ReadLine(); } Пример 6. Работа с массивом элементов структуры в managed - функции Текст программы показан в листинге 14.6, а результат — на рис. 14.6. Рис 14.6. Результат работы с массивом элементов nati ve- структуры в managed - функции Листинг 14.6 // 14.6_2011 Прим 6.cpp : main project file. #include "stdafx.h" #include // unmanaged struct struct ListStruct Глава 14. Преобразование между нерегулируемыми и регулируемыми указателями { int count; double* item; }; #pragma unmanaged void UnmanagedTakesListStruct(ListStruct list) { printf_s("[unmanaged] count = %d\n", list.count); for (int i=0; i #pragma managed int main() { ListStruct list; list.count = 10; list.item =new double[list.count]; /* оператор new размещает объект в куче и возвращает указатель на этот объект. В данном случаев куче формируется одномерный массив из list.count элементов. */ Console::WriteLine("[managed] count = {0}", list.count); создается указатель на объект, формирующий случайные числа Random^ r = gcnew Random(0); /* инициализация массива list.item[] случайными числами из интервала [0,1], умноженными на 100 */ for (int i=0; i Console::WriteLine("array[{0}] = {1}", i, list.item[i]); } вызов функции в функции UnmanagedTakesListStruct(list); Console::ReadLine(); } 482 Часть II. Приложения Windows Пример 7. Доступ к символам в классе Это частный случай примера 3. Здесь интересна работа с указателем, показывающим на строку (строку "обычных" символов) в управляемой куче. Кавычки поставлены для того, чтобы указать на необычность ситуации каждый символ занимает (в отличие от обычной строки символов типа char ) два, а не один байт, т. к. находится в управляемой куче. Поэтому и признак конца — это необычный символа. Текст программы показан в листинге 14.7, а результат — на рис. 14.7. Рис 14.7. Доступ к символам System::String - строки Листинг 14.7 // 14.7_2011 Прим 7.cpp : main project file. #include "stdafx.h" #include { String ^ mystring = "abcdefg"; Описание метода показано в примере 3 */ interior_ptr (L'\0')*/ for ( ; *ppchar != L'\0'; ++ppchar ) Console::Write(*ppchar); Console::Write(L'\n'); переход на новую, после выданной, строку Console::ReadLine(); } Глава 14. Преобразование между нерегулируемыми и регулируемыми указателями Пример 8. Преобразование char в массив Текст программы показан в листинге 14.8, а результат — на рис. 14.8. Рис 14.8. Результат преобразования строки обычных символов в массив System::Byte Листинг 14.8 // 14.8_2011 Прим 8.cpp : main project file. #include "stdafx.h" #include копирование символов char c преобразованием указателя на них во внутренний указатель на них в управляемой куче. Преобразование идет в обычном С-стиле:*/ Marshal::Copy((IntPtr)buf,byteArray, 0, len); вывод (для проверки преобразования) элементов массива с использованием методов класса array:*/ for ( int i = byteArray->GetLowerBound(0); i <= byteArray->GetUpperBound(0); i++ ) { /*byteArray->GetValue(i) выдает указатель на объекта объектами являются элементы массива типа Byte. Поэтому идет преобразование типа. Но внутренний указатель в управляемой куче обладает свойствами обычного С++-указателя, поэтому можно применить операцию разыменования (*), чтобы получить обычный символ char dc = *(Byte^) byteArray->GetValue(i); 484 Часть II. Приложения Windows Form преобразование (С) обычного символа в Юникод-символ, чтобы воспользоваться выводом из класса Console:*/ Console::Write((Char)dc); } выдает стандартный символ окончания строки в стандартный выходной поток Console::WriteLine(); Console::ReadLine(); } Пример 9. Преобразование вили Метод PtrToStringChars() из Vcclr.h можно использовать для преобразования строки в строку типа wchar_t * или char * . Метод возвращает указатель на Юникод-строку, т. к. строки CLR — это строки Юникода. Затем, как показано в примере, вы можете конвертировать "широкую" строку в обычную. Текст программы показан в листинге 14.9, а результат — на рис. 14.9. Рис 14.9. Результат преобразования System::String - строки в wchar_t и char Листинг 14.9 // 14.9_2011 Прим 9.cpp : main project file. #include "stdafx.h" #include < stdio.h > #include < conio.h > #include < stdlib.h > #include < vcclr.h > //for PtrToStringChars() using namespace System; int main() { String ^str = "Hello from our friends!"; Глава 14. Преобразование между нерегулируемыми и регулируемыми указателями преобразование строки в тип wchar_t в управляемой куче и формирование указателя на новую строку (указателя-фиксатора), чтобы строка не переместилась в куче, пока будет идти вызов функции printf():*/ pin_ptr преобразование к типу char *: можно сразу перевести wchar_t * в char *, используя одну из функций-преобразователей WideCharToMultiByte() и wcstombs_s():*/ size_t convertedChars = 0; size_t sizeInBytes = ((str->Length + 1) * 2); errno_t err = 0; выделение памяти в неуправляемой куче под размер строки () ch будет на нее указывать char *ch = (char *)malloc(sizeInBytes); err = wcstombs_s(&convertedChars, //кол-во преобразуемых символов ch, sizeInBytes, адрес, куда они станут записываться wch, адрес, откуда они станут записываться sizeInBytes); количество переписываемых байтов if (err != 0) printf_s("wcstombs_s failed!\n"); printf_s("%s\n", ch); вывод переписанной строки _getch(); } Пример 10. Преобразование в Фирма Microsoft ввела в С+ типы строки. На самом деле — это синонимы класса basic_string , введенные через typedef . Первый тип относится к классу, строки которого (как элементы класса) относятся к типу char , а второй тип — к классу, строки которого (как элементы класса) относятся к типу В табл. 14.2 приведены операторы для работы со строками указанных типов. Таблица Операторы для работы со строками типов и wstring Оператор Описание + Сцепляет две строки Проверяет, неравны ли две строки- операнда Проверяет, равны ли две строки- операнда 486 Часть II. Приложения Windows Таблица 14.2 (окончание) Оператор Описание < Проверяет, меньше ли строка слева от знака оператора строки справа от знака оператора Проверяет, меньше или равна строка слева от знака оператора строки справа от знака оператора Вставляет строку в выходной поток (аналог cout при С+ вводе/выводе) > Проверяет, больше ли строка слева от знака оператора строки справа от знака оператора Проверяет, больше или равна ли строка слева от знака оператора строки справа от знака оператора Извлекает строку из выходного потока (аналог cin при С+ вводе/выводе) swap Если выполнить оператор swap(m1, с этой функцией, тов будет содержимое m2, а в содержимое m1 getline Извлекает строку из входного потока c_str Преобразует string - строку в С- строку Для работы со строками в программе надо выполнить операторы #include и using namespace Пример программы, использующей оператор != , приведен в листинге 14.10, аре- зультат показан на рис. 14.10. Листинг 14.10 // 14.10_2011 Прим 10.cpp : main project file. #include "stdafx.h" #include #include #include { cout << (x? "True": "False") << endl; } int main() { string S1="ABC"; Глава 14. Преобразование между нерегулируемыми и регулируемыми указателями char CP1[]="ABC"; char CP2[]="DEF"; char CP3[]="abc"; cout << "S1 is " << S1 << endl; cout << "CP1 is " << CP1 << endl; cout << "CP2 is " << CP2 << endl; cout << "CP3 is " << CP3 << endl; cout << "S1!=CP1 returned "; trueFalse(S1!=CP1); // False cout << "S1!=CP2 returned "; trueFalse(S1!=CP2); // True cout << "S1!=CP3 returned "; trueFalse(S1!=CP3); // True cout << "CP1!=S1 returned "; trueFalse(CP1!=S1); // False cout << "CP2!=S1 returned "; trueFalse(CP2!=S1); // True cout << "CP3!=S1 returned "; trueFalse(CP3!=S1); // True _getch(); } Строки String — это последовательности Юникод-символов. Программа, использующая маршалинг для преобразования строк типа String в строки типа string и wstring , приведена в листинге 14.11, а результат ее работы показан на рис. 14.11. Рис 14.10. Результат работы программы, указанной в листинге Рис 14.11. Результат работы со строками String , string и wstring 488 Часть II. Приложения Windows Листинг 14.11 // 14.11_2011 Прим 11.cpp : main project file. #include "stdafx.h" #include #include #include //----------------- функция копирует s в os типа string -------------------- void MarshalString ( String ^ s, string & os ) { /*Маршал-метод копирует содержимое строки в неуправляемую память (кучу) и выдает указатель типа void для его последующего преобразования в необходимый тип (в данном случаев указатель на строку с символами char:*/ os = chars; освобождение памяти в неуправляемой куче, которую занимает строка Marshal::FreeHGlobal(IntPtr((void*)chars)); } //----------------- функция копирует s в os типа wstring -------------- void MarshalString ( String ^ s, wstring & os ) { /*Маршал-метод копирует содержимое строки в неуправляемую память (кучу) и выдает указатель типа void для его последующего преобразования в необходимый тип (в данном случаев теперь можно присвоить, т.к. переменные одного типа освобождение памяти в неуправляемой куче, которую занимает строка Marshal::FreeHGlobal(IntPtr((void*)chars)); } int main() { string a = "test"; wstring b = L"test2"; широкая" строка (по 2 байта на символ) String ^ c = gcnew String("abcd"); Глава 14. Преобразование между нерегулируемыми и регулируемыми указателями cout << a << endl; вывод строки а MarshalString(c, a); перезапись св а c = "efgh"; MarshalString(c, b); перезапись св вывода вывод b _getch(); } Пример 11. Преобразование строки в |