Runtime c что это
Не могу найти подробную информацию о том, что такое CRT и зачем она нужна.
Чтобы было проще и больше конкретики ограничимся Виндой И компилятором языка Си, что стоит в студии.
Как я понимаю из уже прочитанной информации CRT- библиотека, которая неявно компилируется линкуется вместе с почти любой программой. Нужна она для того чтобы поддерживать программу, во время выполнения.
Какая то прослойка системных вызовов. И я совершенно не понимаю зачем это нужно. Зачем нужна эта прослойка ?
Почему компилятор просто не преобразовывает функции программы вроде malloc и fopen в системные вызовы, зачем нужна какая то прослойка, которую еще и таскать с собой надо, которая еще и не динамическая.
Еще я слышал, что можно даже вроде как написать свою CRT для программы, если сильно захочется. Как это сделать и как это работает ?
Было бы интересно посмотреть на конкретную реализацию CRT что стоит в студии. Или в Gcc, где ее искать ?
Нужна ли подобная библиотека времени выполнения программам написанным на ASM ?
Например скомпилированных MASM.
Ну в гугле в википедии что ли забанили? CRT/RTL.
Для ассемблера такого не надо, там всё делаешь руками, сам, под каждый процессор и под каждую OS. А язык C и является переносимым по большей части как раз из-за наличия CRT. malloc и fopen в языке C везде одинаковы, но всегда разные для конкретной OS .
Свою CRT написать можно, но это требуется довольно редко и для весьма конкретных и специфических случаев.
Если интересно посмотреть на конкретную реализацию CRT что стоит в студии, то она поставляется вместе со студией в виде исходных текстов, хоть обсмотрись.
Нет, не забанили. Я там почти ничего не понял, слишком мало информации, слишком непонятно. Так же как и на других ресурсах англо и русскоязычных.
Что значит переносимым ? Результатом работы компилятора и линковщика студии является обычный PE файл. PE файл не запустится на linux. Там нужен формат elf. О какой переносимости речь, я не понимаю.
Для винды malloc и fopen всегда одинаковы, это одни и те же системные вызовы.
Си это не язык Java, Java файл заработает и на винде и на линуске потому что для каждой Ос будет своя JVM, в которой запускается программа.
RoflanDaniil, компилятор не знает и не должен знать, что делает функция, даже если она из системной библиотеки, он должен знать только о том, как её вызывать (какого типа аргументы, в каком порядке передавать…).
И их аргументы (их типы, последовательность передачи и т. п.) полностью совпадают? Если нет, то нужна прослойка.
RoflanDaniil, переносимость исходных текстов. Между API вантуза и линукса такого нет и быть не может. А через CRT очень даже может.
pfemidi, ну такая же функция у стандартной библиотеки. Для каждой ОС у каждого компилятора своя стандартная библиотека. malloc и fopen это просто фукнции. Которые в своем коде должны делать системные вызовы.
А для CRT почему то именно выделяют от стандартной библиотеки. И еще заставляют таскать с собой всю библиотеку, даже если программе нужна только одна функция.
RoflanDaniil, malloc и fopen и есть функции из стандартной библиотеки, которые внутри себя дёргают системные вызовы. Но внешне и malloc, и fopen одинаковы в какой бы OS не компилировался исходный текст программы. Поэтому
одинаково хорошо скомпилируется и в Linux, и в Windows, и в QNX, и ещё чёрт знает где, а (упрощённо):
будет компилироваться только в Windows.
И всю библиотеку с собой никто не таскает, таскают только те функции, которые используются в программе. Например если в программе используется только malloc, то код scanf в программу не попадёт.
А CRT помимо того что содержит в себе все функции стандартной библиотеки так же выполняет начальную настройку для дальнейшей благополучной работы этих функций из стандартной библиотеки: устанавливает stack, устанавливает heap, обнуляет статические переменные, регистрирует необходимые обработчики исключений и т.д.
Как уже правильно советовал Illia Nezhyhai про glibc надо почитать. Ну или изучить исходники от Visual Studio как я уже говорил. Потому что рассказывать об этом долго и нудно, лучше уж будет самому один раз увидеть что это такое.
CRT - это реализация стандартной библиотеки Си/С++ для данного компилятора.
ОС обычно пишутся на Си и если в ОС нет реализации функций из стандарта Си, то они реализуются в стандартной библиотеке. Все классы из stdlib С++ реализованы в CRT.
CRT в VS может линковаться как статически так и динамически, в зависимости от опций компилятора. Линкуете статически - у вас распухает ваш исполняемый файл, динамически - пользователь должен предварительно поставить соответствующий vcredist (установку можно встроить в собственный инсталлятор). С точки зрения производительности оба варианта примерно одинаковы.
Вы можете не использовать стандартную библиотеку в принципе (отключив ее опциями компилятора) и работать на прямую с ОС, но это накладывает много ограничений и вы фактически остаетесь с кастрированным вариантом ЯП, т.к. например в С++ даже стандартный new/delete, на сколько я знаю, реализованы в стандартной библиотеке и прямого аналога в ОС нет. Обычно этим никто не заморачивается из-за возникающих проблем, решение которых заметно увеличит время реализации проекта, разве что вам необходимо сделать исполняемый файл минимального размера, максимально быстро стартующий и без зависимостей.
Многое, что вы написали у меня вызывает противоречия.
new/delete нужны чтобы работать с памятью кучи. Для работы с кучей есть специальные системные вызовы.
то есть они должны переводиться компилятором, в эти самые системные вызовы. Больше способов работы с кучей из user mode вроде нет. Тоесть не важно пишу я new /delete или просто системные вызовы heapCreate/heapDestroy. Результатом компиляции должен быть PE файл в котором в секции .text находятся вызовы heapCreate/heapDestroy.
Вы способны самостоятельно сделать системный вызов? Самый банальный open(), например, вот попробуйте, сделайте без рантайма.
В этой статье описывается, как использовать время выполнения C.
Исходная версия продукта: Visual C++
Исходный номер базы знаний: 94248
в этом разделе
Подпрограммы универсальной среды выполнения C по категориям
Предоставляет ссылки на библиотеку времени выполнения по категориям.
Глобальные переменные и стандартные типы
Предоставляет ссылки на глобальные переменные и стандартные типы, предоставляемые библиотекой времени выполнения.
Глобальные константы
Предоставляет ссылки на глобальные константы, определяемые библиотекой времени выполнения.
Глобальное состояние
Описывает область глобального состояния в библиотеке времени выполнения C.
Универсальные текстовые сопоставления
Содержит ссылки на универсальные текстовые сопоставления, определенные в файле Tchar.h.
Алфавитный указатель функций
Содержит ссылки на функции библиотеки времени выполнения C, упорядоченные в алфавитном порядке.
Общие сведения о семействе функций
Содержит ссылки на функции библиотеки времени выполнения C, упорядоченные по семейству функций.
Строки языка и страны или региона
Описывает способы использования функции setlocale для задания языка и строк страны или региона.
Файлы среды выполнения C (CRT) и библиотеки стандартных библиотек C++ (STL) .lib
.lib Список файлов, составляющих библиотеки времени выполнения C и связанные с ними параметры компилятора и директивы препроцессора.
Раздел 5. Смешивание типов библиотек
Библиотеку DLL можно связать с CRTDLL. LIB/MSVCRT. LIB независимо от того, с каким .EXE связан ваш файл, если вы не смешивали структуры данных CRT и не передавая дескрипторам файлов CRT или указателям CRT FILE* на другие модули.
При смешивании типов библиотек придерживайтесь следующих параметров:
Дескрипторами файлов CRT может работать только модуль CRT, который их создал.
Указатели CRT FILE* могут использоваться только модулем CRT, который их создал.
Память, выделенная с помощью функции CRT malloc() , может быть освобождена или перенаполнина только выделенным модулем CRT.
Чтобы проиллюстрировать это, рассмотрим следующий пример:
- .EXE связан с MSVCRT. LIB
- Библиотека DLL A связана с LIBCMT. LIB
- Библиотека DLL B связана с CRTDLL. LIB
Если .EXE создает дескриптора CRT-файла _create() _open() с помощью или, _lseek() этот дескриптора файла может передаваться только в , _read() , и _write()``_close() т. д. в .EXE файла. Не передайте этот дескриптора CRT-файла ни в библиотеку DLL. Не передавайте дескриптора файла CRT, полученного из библиотеки DLL, в другую библиотеку DLL или в .EXE.
Если библиотека DLL A malloc() выделяет блок памяти, только библиотека DLL A free()``_expand()``realloc() может вызывать или работать с этим блоком. Вы не можете вызвать malloc() библиотеку DLL A и попытаться освободить этот блок из .EXE или из библиотеки DLL B.
Если все три модуля были связаны с CRTDLL. LIB или все три были связаны с MSVCRT. LIb, эти ограничения не применяются.
При связывание библиотек DLL с LIBC. Следует помнить, что если существует вероятность того, что такая библиотека DLL будет вызвана многопоточной программой, библиотека DLL не будет поддерживать несколько потоков, выполняющихся в библиотеке DLL одновременно, что может привести к возникновению основных проблем. Если существует вероятность того, что библиотека DLL будет вызываться многопоточными программами, обязательно свяжите ее с одной из библиотек, поддерживающих многопоточные программы (LIBCMT). LIB, CRTDLL. LIB или MSVCRT. LIB).
библиотека среды выполнения microsoft предоставляет подпрограммы для программирования операционной системы microsoft Windows. Эти процедуры автоматизируют выполнение многих распространенных задач программирования, которые не предоставляются языками C и C++.
В справочные разделы включены примеры программ для большинства подпрограмм из библиотеки.
Раздел 2. Использование библиотек CRT при создании библиотеки DLL
При создании библиотеки DLL, которая использует любую из библиотек времени выполнения C, чтобы обеспечить правильную инициализацию CRT, выполните одно из следующих действий:
Функция инициализации должна иметь имя DllMain() , а точка входа должна быть указана с помощью параметра компоновщика. -entry:_DllMainCRTStartup@12
Точка входа библиотеки DLL должна явно CRT_INIT() вызывать присоединение процессов и отсоединения процессов.
Это позволяет библиотекам времени выполнения C правильно выделять и инициализировать данные времени выполнения C при подключении процесса или потока к библиотеке DLL, правильно очищать данные времени выполнения C при отсоединении процесса от библиотеки DLL, а также правильно создавать и деструкировать глобальные объекты C++ в библиотеке DLL.
В примерах пакета SDK win32 используется первый метод. Используйте их в качестве примера. Также ознакомьтесь со справочником программиста Win32 DllEntryPoint() и документацией по Visual C++ для DllMain() . Обратите внимание, DllMainCRTStartup() что CRT_INIT() вызывается CRT_INIT() и вызывается DllMain() приложения, если оно существует.
Если вы хотите использовать второй метод и вызвать код инициализации CRT самостоятельно, а не использовать DllMainCRTStartup() DllMain() и, существует два метода:
Если нет входной функции, которая выполняет код инициализации, CRT_INIT() укажите ее в качестве точки входа библиотеки DLL. Предположим, что вы включили NTWIN32. MAK, который определяется DLLENTRY как @12, добавьте параметр в строку ссылки библиотеки DLL: -entry:_CRT_INIT$(DLLENTRY) .
Если у вас есть собственная точка входа DLL, выполните следующие действия в точке входа:
Используйте этот прототип для: CRT_INIT()``BOOL WINAPI _CRT_INIT(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
Сведения о возвращаемых CRT_INIT() значениях см. в документации по DllEntryPoint. Возвращаются те же значения.
DLL_PROCESS_ATTACH DLL_THREAD_ATTACH Включите и (см. DllEntryPoint в справочнике по API Win32, чтобы получить дополнительные сведения об этих флагах), CRT_INIT() сначала вызовите перед вызовом любых функций времени выполнения C или выполнения любых операций с плавающей запятой.
Вызовите собственный код инициализации или завершения процесса или потока.
После DLL_PROCESS_DETACH вызова DLL_THREAD_DETACH всех CRT_INIT() функций времени выполнения C и завершения всех операций с плавающей запятой включи и последнего вызова.
CRT_INIT() Обязательно передайте все параметры точки входа; CRT_INIT() ожидает эти параметры, поэтому все может не работать надежно, если они опущены (в частности, для определения необходимости инициализации или завершения процесса требуется fdwReason).
Ниже приведен пример функции точек CRT_INIT() входа, который показывает, когда и как выполнять эти вызовы в точке входа DLL:
Это необязательно, если вы используете и DllMain() -entry:_DllMainCRTStartup@12 .
Раздел 1. Доступны три формы библиотек C Run-Time (CRT)
Существует три формы библиотеки времени выполнения C, предоставляемой пакетом SDK для Win32:
LIBC. LIB — это статически связанная библиотека для однопотокных программ.
LIBCMT. LIB — это статически связанная библиотека, которая поддерживает многопоточные программы.
CRTDLL. LIB — это библиотека импорта для CRTDLL.DLL, которая также поддерживает многопоточные программы. CRTDLL.DLL является частью Windows NT.
Microsoft Visual C++ 32-разрядный выпуск также содержит эти три формы, однако CRT в библиотеке DLL называется MSVCRT. LIB. Библиотека DLL является распространяемой. Его имя зависит от версии VC++ (то есть MSVCRT10.DLL или MSVCRT20.DLL). Обратите внимание, что MSVCRT10.DLL не поддерживается в Win32s, в то время как CRTDLL. Lib поддерживается в Win32s. MSVCRT20.DLL версии: одна для Windows NT другая для Win32s.
Раздел 4. Проблемы, возникающие при использовании нескольких библиотек CRT
Если приложение, которое выполняет вызовы среды выполнения C, ссылается на библиотеку DLL, которая также выполняет вызовы среды выполнения C, имейте в виду, что если они связаны с одной из статически связанных библиотек времени выполнения C (LIBC). LIB или LIBCMT. LIB), .EXE и DLL будут иметь отдельные копии всех функций времени выполнения C и глобальных переменных. Это означает, что данные времени выполнения C нельзя совместно использовать между .EXE и библиотекой DLL. Ниже перечислены некоторые проблемы, которые могут возникнуть в результате.
Передача дескриптора буферизованного потока из .EXE/DLL в другой модуль
Выделение памяти с помощью вызова среды выполнения C в библиотеке .EXE/DLL и ее перераспределение или освобождение в другом модуле
Проверка или задание значения глобальной переменной errno в .EXE/DLL и ожидается, что оно будет совпадать в другом модуле. Связанная проблема заключается в вызове perror() в обратном модуле, из которого произошла ошибка времени выполнения C, perror() так как используется errno.
Чтобы избежать этих проблем, свяжите библиотеку .EXE DLL с CRTDLL. LIB или MSVCRT. LIB, который позволяет библиотеке .EXE и библиотеке DLL использовать общий набор функций и данных, содержащихся в CRT в библиотеке DLL, а данные времени выполнения C, такие как дескриптора потока, могут совместно использоваться как .EXE, так и DLL.
Раздел 3. Использование NTWIN32. Mak для упрощения процесса сборки
В NTWIN32 определены макросы. MAK, который можно использовать для упрощения файлов makefile и обеспечения их правильной сборки во избежание конфликтов. По этой причине корпорация Майкрософт настоятельно рекомендует использовать NTWIN32. MAK и макросы в них.
Для компиляции используйте: $(cvarsdll) for apps/DLLs using CRT in a DLL .
Для связывания используйте один из следующих способов:
- $(conlibsdll) for console apps/DLLs using CRT in a DLL
- $(guilibsdll) for GUI apps using CRT in a DLL
Связанные разделы
Подпрограммы отладки
Содержит ссылки на отладочные версии подпрограмм библиотеки среды выполнения.
Проверка ошибок времени выполнения
Содержит ссылки на функции, поддерживающие проверки ошибок во время выполнения.
Отладка
Ссылки на разделы, описывающие использование отладчика Visual Studio для устранения логических ошибок в приложениях и хранимых процедурах.
В данном посте я хочу обратиться к теме, о которой многие начинающие iPhone-разработчики часто имеют смутное представление: Objective-C Runtime. Многие знают, что он существует, но каковы его возможности и как его использовать на практике?
Попробуем разобраться в базовых функциях этой библиотеки. Материал основан на лекциях, которые мы в Coalla используем для обучения сотрудников.
Что такое Runtime?
Objective-C задумывался как надстройка над языком C, добавляющая к нему поддержку объектно-ориентированной парадигмы. Фактически, с точки зрения синтаксиса, Objective-C — это достаточно небольшой набор ключевых слов и управляющих конструкций над обычным C. Именно Runtime, библиотека времени выполнения, предоставляет тот набор функций, которые вдыхают в язык жизнь, реализуя его динамические возможности и обеспечивая функционирование ООП.
Базовые структуры данных
Функции и структуры Runtime-библиотеки определены в нескольких заголовочных файлах: objc.h , runtime.h и message.h . Сначала обратимся к файлу objc.h и посмотрим, что представляет из себя объект с точки зрения Runtime:
Мы видим, что объект в процессе работы программы представлен обычной C-структурой. Каждый Objective-C объект имеет ссылку на свой класс — так называемый isa-указатель. Думаю, все видели его при просмотре структуры объектов во время отладки приложений. В свою очередь, класс также представляет из себя аналогичную структуру:
Класс в Objective-C — это полноценный объект и у него тоже присутствует isa-указатель на «класс класса», так называемый метакласс в терминах Objective-C. Аналогично, С-структуры определены и для других сущностей языка:
Функции Runtime-библиотеки
- Манипулирование классами: class_addMethod , class_addIvar , class_replaceMethod
- Создание новых классов: class_allocateClassPair , class_registerClassPair
- Интроспекция: class_getName , class_getSuperclass , class_getInstanceVariable , class_getProperty , class_copyMethodList , class_copyIvarList , class_copyPropertyList
- Манипулирование объектами: objc_msgSend , objc_getClass , object_copy
- Работа с ассоциативными ссылками
Пример 1. Интроспекция объекта
Рассмотрим пример использования Runtime библиотеки. В одном из наших проектов модель данных представляет собой plain old Objective-C объекты с некоторым набором свойств:
Для удобства отладки хотелось бы, чтобы при выводе в лог печаталась информация о состоянии свойств объекта, а не нечто вроде . Поскольку модель данных достаточно разветвленная, с большим количеством различных подклассов, нежелательно писать для каждого класса отдельный метод description , в котором вручную собирать значения его свойств. На помощь приходит Objective-C Runtime:
Метод, определенный в общем суперклассе объектов модели, получает список всех свойств объекта с помощью функции class_copyPropertyList . Затем значения свойств собираются в NSDictionary , который и используется при построении строкового представления объекта. Данный алгоритм раработает только со свойствами, которые являются Objective-C объектами. Проверка типа осуществляется с использованием функции property_getAttributes . Результат работы метода выглядит примерно так:
2013-05-04 15:54:01.992 Test[40675:11303] COConcreteObject: name = Foo;
quantity = 10;
title = bar;
>
Вызов objc_msgSent инициирует процесс поиска реализации метода, соответствующего селектору, переданному в функцию. Реализация метода ищется в так называемой таблице диспетчеризации класса. Поскольку этот процесс может быть достаточно продолжительным, с каждым классом ассоциирован кеш методов. После первого вызова любого метода, результат поиска его реализации будет закеширован в классе. Если реализация метода не найдена в самом классе, дальше поиск продолжается вверх по иерархии наследования — в суперклассах данного класса. Если же и при поиске по иерархии результат не достигнут, в дело вступает механизм динамического поиска — вызывается один из специальных методов: resolveInstanceMethod или resolveClassMethod . Переопределение этих методов — одна из последних возможностей повлиять на Runtime:
Пример 2. Method Swizzling
Одна из особенностей категорий в Objective-C — метод, определенный в категории, полностью перекрывает метод базового класса. Иногда нам требуется не переопределить, а расширить функционал имеющегося метода. Пусть, например, по каким-то причинам нам хочется залогировать все добавления элементов в массив NSMutableArray . Стандартными средствами языка этого сделать не получится. Но мы можем использовать прием под названием method swizzling:
Мы перегружаем метод load — это специальный callback, который, если он определен в классе, будет вызван во время инициализации этого класса — до вызова любого из других его методов. Здесь мы меняем местами реализацию базового метода addObject: и нашего метода logAddObject: . Обратите внимание на «рекурсивный» вызов в logAddObject: — это и есть обращение к перегруженной реализации основного метода.
Пример 3. Ассоциативные ссылки
Еще одним известным ограничением категорий является невозможность создания в них новых переменных экземпляра. Пусть, например, вам требуется добавить новое свойство к библиотечному классу UITableView — ссылку на «заглушку», которая будет показываться, когда таблица пуста:
«Из коробки» этот код работать не будет, вы получите исключение во время выполнения программы. Эту проблему можно обойти, используя функционал ассоциативных ссылок:
Любой объект вы можете использовать как ассоциативный массив, связывая с ним другие объекты с помощью функции objc_setAssociatedObject . Для ее работы требуется ключ, по которому вы потом сможете извлечь нужный вам объект назад, используя вызов objc_getAssociatedObject . При этом вы не можете использовать скопированное значение ключа — это должен быть именно тот объект (в примере — указатель), который был передан в вызове objc_setAssociatedObject .
Метаданные Windows Runtime
Тем не менее, метаданные, которые описывают этот тип позволяют CLR получить экземпляр реализации при вызове конструктора класса.
При просмотре Windows Runtime метаданных можно также заметить, что определения типов и сборок используют новое ключевое слово WindowsRuntime.
Это ключевое слово является контекстно-зависимым и по разному интерпретируется в зависимости от того, где оно применяется. Например, если ключевым словом помечено определение типа (TypeDef), то этот тип подчиняется правилам системы типов Windows Runtime и вызов этого типа следует рассматривать как вызов WinRT API.
Взаимодействие CLR с компонентами WinRT
CRL поддерживает взаимодействие с COM-компонентами через обертки Runtime Callable Wrapper (RCW) и COM Callable Wrapper (CCW). Таким образом в CLR ссылка на WinRT объект представляет собой ссылку на RCW, которая в свою очередь содержит ссылку на WinRT объект. Соответственно управляемый код взаимодействует с RCW, который по сути является интерфейсом между вашим кодом и WinRT объектом.
Аналогичным образом в Windows Runtime ссылка на объект CLR представляет собой ссылку на CCW, которая в свою очередь содержит ссылку на CLR объект. Windows Runtime при этом взаимодействует с CCW для доступа к функциональности управляемого объекта.
WinRT типы и управляемый код
Проецирование типов
Базовый тип
Структуры
Структуры WinRT, в отличие от значимых типов CLR, могут содержать только открытые поля одного из базовых типов или же являться другой структурой WinRT. Таким образом, следующий код выдаст ошибку на этапе компиляции:
К тому же, структуры WinRT не могут определять конструкторы или содержать вспомогательные методы. Однако, некоторые структуры CLR, для удобства, проецирует на свои собственные, тем самым предоставляя разработчикам вспомогательные методы и конструкторы. К таким относятся, например, структура Windows.Foundation.Point, Windows.Foundation.Size и Windows.Foundation.Rect.
Строки
Null-совместимые типы
то в управляемом коде этот метод будет выглядеть следующим образом:
Делегаты
В качестве типа параметра или возвращаемого значения делегата WinRT могут использовать только WinRT-совместимые типы. Так же делегаты с глобальной (public) областью видимости не могут быть объявлены как вложенные (на самом деле это общие правила для среды выполнения Windows в целом). Когда вы передаете объект делегата компоненту Windows Runtime, этот объект упаковывается в обертку CCW, которая не уничтожается сборщиком мусора до тех пор, пока она не будет освобождена компонентом, который ее использует. Интересен так же тот факт, что делегаты WinRT не имеют методов BeginInvoke и EndInvoke.
События
то при компиляции этой строки кода, компилятор превращает ее в следующие инструкции:
Для того, чтобы вызывать событие, следует воспользоваться свойством InvocationList, возвращающее делегат, список вызовов которого включает в себя все делегаты, добавленные в качестве обработчиков события.
Время и дата
В WinRT время и дата представляются в формате UTC структурой Windows.Foundation.DateTime. CLR проецирует данный тип на структуру System.DateTimeOffset, а не на System.DateTime. Стоит заметить, что DateTime не содержит информацию о часовом поясе. Поэтому дата и время, возвращаемые функциями WinRT в формате UTC, CLR преобразует в локальное время. И наоборот, при передаче структуры DateTimeOffset в WinRT функцию, дата и время преобразуются в UTC формат.
Массивы
WinRT API поддерживает только одномерные массивы. Соответственно следующий код вызовет ошибку времени компиляции:
Коллекции
При передачи коллекции CLR упаковывает объект коллекции в обертку CCW и передает ссылку на нее в WinRT API. При этом вызовы через обертку пересекают границу взаимодействия, что отрицательно сказывается на производительности. Однако, в отличие от массивов, возможно выполнение операций без копирования элементов.
Заключение
Подводя итоги, отмечу, что благодаря изменениям в CLR, разработчики управляемого кода могут легко адаптироваться к новому Windows Runtime API, используя знакомые им технологии. В данной статье я описал далеко не все подробности взаимодействия WinRT и CLR. Однако, это может послужить основой для дальнейшего изучения и более глубоко понимания Windows Runtime.
Читайте также: