Скачать презентацию Опасный код С позволяет программистам писать то что Скачать презентацию Опасный код С позволяет программистам писать то что

Лекция 11(оп код).ppt

  • Количество слайдов: 26

Опасный код С# позволяет программистам писать то, что называется Опасный код С# позволяет программистам писать то, что называется "опасный кодом" (unsafecode). Опасный код — это код, который не выполняется под полным управлением системы Common Language Runtime (CLR).

Причины использования опасного кода. Управляемый код не допускает использование указателей. Указатели — это переменные, Причины использования опасного кода. Управляемый код не допускает использование указателей. Указатели — это переменные, которые хранят адреса других объектов. Указатели в некотором роде подобны ссылкам в С#. Основное различие между ними заключается в том, что указатель может указывать на что угодно в памяти, а ссылка всегда указывает на объект "своего" типа. Но если указатель может указывать на что угодно, возможно неправильное его использование. Кроме того, работая с указателями, можно легко внести в код ошибку, которую будет трудно отыскать. Тем не менее указатели существуют, причем для некоторых типов программ (например, системных утилит) -они — необходимы.

Программирование опасного кода • Все операции с указателями должны быть отмечены как Программирование опасного кода • Все операции с указателями должны быть отмечены как "опасные", поскольку они выполняются вне управляемого контекста. • Объявление и использование указателей в С# происходит аналогично тому, как это делается в C/C++. Однако: особенность С# — создание управляемого кода. • Его способность поддерживать неуправляемый код позволяет применять программы к задачам специальной категории. Но такое С# программирование уже не подпадает под определение стандартного. И в самом деле, чтобы скомпилировать неуправляемый код, необходимо использовать опцию компилятора /unsafe.

Использование указателей Указатели — это переменные, которые хранят адреса других переменных. Формат объявления переменной-указателя: Использование указателей Указатели — это переменные, которые хранят адреса других переменных. Формат объявления переменной-указателя: ТИП* имя_переменной; int* ip; float* fp; Здесь переменную ip можно использовать для указания на int-значение, а переменную fp — на float-значение. Однако не существует реального средства, которое могло бы помешать указателю указывать на"бог-знает-что". Вот потому-то указатели потенциально опасны.

Различие между способами объявления указателей в С# и C/C++ При объявлении типа указателя в Различие между способами объявления указателей в С# и C/C++ При объявлении типа указателя в C/C++ оператор " * " не распространяется на весь список переменных, участвующих в объявлении. То есть C/C++ при выполнении инструкции int* p, q; объявляется указатель р на int-значение и int-переменная с именем q. Эта инструкция эквивалентна объявлениям: int* p ; int q; В C# инструкция эквивалентна объявлениям: int* р; int* q;

Операторы Операторы "*" и "&" Оператор "&" — унарный. Он возвращает адрес памяти, по которому расположен его операнд. Пример int * i p ; int num = 10; ip = # Оператор работы с указателями (*) служит дополнением к первому (&) он указывает на значение переменной, адресуемой заданным указателем int val = *ip; Оператор "*" также можно использовать с левой стороны от оператора присваивания. *ip = 100;

Использование ключевого слова unsafe Код, в котором используются указатели, должен быть отмечен как Использование ключевого слова unsafe Код, в котором используются указатели, должен быть отмечен как "опасный" с помощью ключевого слова unsafe. Так можно отмечать отдельные инструкции и методы целиком.

Пример using System; class Unsafe. Code { unsafe public static void Main() { int Пример using System; class Unsafe. Code { unsafe public static void Main() { int count = 99; int* p; р = &count; Console. Write. Line("count= " +*p); *р = 10; Console. Write. Line("Новый count= " + *р); } }

Использование модификатора fixed При работе с указателями часто используется модификатор fixed. Он предотвращает удаление Использование модификатора fixed При работе с указателями часто используется модификатор fixed. Он предотвращает удаление управляемых переменных системой сбора мусора. Это необходимо втом случае, если, например, указатель ссылается на какое-нибудь поле в объекте класса. Поскольку указатель "ничего не знает" о действиях "сборщика мусора", то в случае удаления такого объекта этот указатель будет указывать на неверный объект. fixed (type* p = &var) { // Использование зафиксированного объекта. }

Пример использования модификатора fixed using System; class Test { public int num; public Test(int Пример использования модификатора fixed using System; class Test { public int num; public Test(int i) { num = i ; } class Fixed. Code { unsafe public static void Main() { Test Sо = new Test(19); fixed (int* p = So. num) {Console. Write. Line("Начальное значение поля So. num равно " + *р); *р = 10; Console. Write. Line("Новое значение поля So. num равно " + *р); }}}

Доступ к членам структур с помощью указателей Указатель может ссылаться на объект структурного типа, Доступ к членам структур с помощью указателей Указатель может ссылаться на объект структурного типа, если он не содержит ссылочных типов. При доступе к члену структуры посредством указателя необходимо использовать оператор "стрелка" (->)

Пример struct My. Struct { public int x; public int y; public int sum() Пример struct My. Struct { public int x; public int y; public int sum() { return x + y; } } ---------My. Struct о = new My. Struct ( ) ; My. Struct* p; // Объявляем указатель. р = & о; р->х = 10; р->у = 20; Console. Write. Line("Сумма равна " + p->sum());

Арифметические операции над указателями С указателями можно использовать : ++, --, + и -. Арифметические операции над указателями С указателями можно использовать : ++, --, + и -. int* p; p =2000; p++; //p =? p=p+9; //p =? Несмотря на то что складывать указатели нельзя, один указатель можно вычесть из другого(если они оба имеют один базовый тип). Разность покажет количество элементов базового типа, которые разделяют эти два указателя. Помимо сложения (и вычитания) указателя и (из) целочисленного значения, а также вычитания двух указателей, над указателями никакие другие арифметические операции не выполняются. Например, с указателями нельзя складывать float- или double-значения.

Пример using System; class Ptr. Arith. Demo { unsafe public static void Main() { Пример using System; class Ptr. Arith. Demo { unsafe public static void Main() { int x; int i; double d; int* ip = &i; double* fp = &d; Console. Write. Line("int doublen"); for(x=0; x < 10; x++) { Console. Write. Line((uint) (ip) + " " +(uint) (fp)); fp++; ip++; } }}

Сравнение указателей Для сравнения указателей любого типа можно использовать следующие операторы: == != < Сравнение указателей Для сравнения указателей любого типа можно использовать следующие операторы: == != < > <= >=. Операторы сравнения сравнивают адреса двух операндов, как если бы они были беззнаковыми целыми числами. Для того чтобы результат сравнения указателей поддавался интерпретации, сравниваемые указатели должны быть какимто образом связаны. То есть, если pi и р2 указывают на переменные, между которыми существует некоторая связь (как, например, между элементами одного и того же массива), то результат сравнения указателей pi и р2 может иметь определенный смысл.

Пример using System; class Ptr. Comp. Demo { unsafe public static void Main() { Пример using System; class Ptr. Comp. Demo { unsafe public static void Main() { int[] nums = new int[11]; int x; // Находим средний элемент массива, fixed (int* start = &nums[0]) { fixed(int* end = &nums[nums. Length-1]) { for(x=0; start+x <= end-x; x++) ; } } Console. Write. Line( "Средний элемент массива имеет номер " + х ) ; }}

Указатели и массивы В С# указатели и массивы связаны между собой. Например, имя массива Указатели и массивы В С# указатели и массивы связаны между собой. Например, имя массива без индекса образует указатель на начало этого массива. • using System; class Ptr. Array { unsafe public static void Main() { int[] nums = new int[10]; fixed(int* p = &nums[0]; p 2 = nums; ) { if(p == p 2) Console. Write. Line("Указатели р и р2 равны"); }}}

Индексация указателя Указатель, который ссылается на массив, можно индексировать так, как если бы это Индексация указателя Указатель, который ссылается на массив, можно индексировать так, как если бы это было имя массива. Этот синтаксис обеспечивает альтернативу арифметическим операциям над указателями, поскольку он более удобен в некоторых ситуациях. (ptr + i) эквивалентно ptr[i] При индексировании указателя необходимо помнить следующее. Во-первых, при этом нарушение границ массива никак не контролируется. Следовательно, существует возможность получить доступ к "элементу" за концом массива, если на него ссылается указатель. Во-вторых, указатель не имеет свойства Length. Поэтому при использовании указателя невозможно узнать длину массива.

Указатели и строки Несмотря на то что в С# строки реализованы как объекты, к Указатели и строки Несмотря на то что в С# строки реализованы как объекты, к отдельным их символам можно получить доступ с помощью указателя. Для этого достаточно присвоить char*-указателю адрес начала этой строки, используя fixed-инструкцию: fixed(char* p = str ) { II. . .

Массивы указателей Указатели, подобно данным других типов, могут храниться в массивах. int * [ Массивы указателей Указатели, подобно данным других типов, могут храниться в массивах. int * [ ] p t r s = new int * [3]; Чтобы присвоить адрес int-переменной с именем var третьему элементу этого массива указателей, запишите следующее: ptrs[2] = &var; Чтобы получить значение переменной var, используйте такой синтаксис: *ptrs[2]

sizeof -Для получения размера (в байтах) одного из С#-типов значений. sizeof(тип) Оператор sizeof можно sizeof -Для получения размера (в байтах) одного из С#-типов значений. sizeof(тип) Оператор sizeof можно использовать только в контексте опасного (unsafe) кода. Таким образом, он предназначен в основном для специальных ситуаций, особенно при работе со смешанным (управляемым и неуправляемым) кодом. NB Начиная с версии 2. 0 языка C# применении оператора sizeof к встроенным типам больше не требуется использовать небезопасный режим.

BoxingUnboxing Упаковка-преобразование представляет собой процесс преобразования типа значения в тип object или любой другой BoxingUnboxing Упаковка-преобразование представляет собой процесс преобразования типа значения в тип object или любой другой тип интерфейса, реализуемый этим типом значения. Когда тип значения упаковывается средой CLR, она создает программу-оболочку значения внутри System. Object и сохраняет ее в управляемой куче. Операция распаковки-преобразования извлекает тип значения из объекта. Упаковка-преобразование является неявной; распаковка-преобразование является явной. Концепция упаковки и распаковки лежит в основе единой системы типов C#, в которой значение любого типа можно рассматривать как объект.

Пример • Упаковка int i = 123; // The following line boxes i. object Пример • Упаковка int i = 123; // The following line boxes i. object o = i; Распаковка o = 123; i = (int)o; // unboxing

Упаковка int i = 123; object o = i; Упаковка int i = 123; object o = i;

Распаковка int i = 123; // a value type object o = i; // Распаковка int i = 123; // a value type object o = i; // boxing int j = (int)o; // unboxing

Резюме По сравнению с простыми операциями присваивания операции упаковки-преобразования и распаковкипреобразования являются весьма затратными Резюме По сравнению с простыми операциями присваивания операции упаковки-преобразования и распаковкипреобразования являются весьма затратными процессами с точки зрения вычислений. При выполнении упаковки-преобразования типа значения необходимо создать и разместить новый объект. Объем вычислений при выполнении операции распаковки-преобразования, хотя и в меньшей степени, но тоже весьма значителен