В языке программирования C# ключевое слово unsafe используется для определения "небезопасного" контекста, в котором вы можете использовать "небезопасные функции» или "небезопасные операции», которые обычно не доступны в "безопасном" коде C#.
Отметим, что чтобы скомпилировать код с unsafe блоками или методами, вам нужно включить поддержку unsafe кода в своих настройках проекта.
Использование ключевого слова Unsafe может быть опасным, поскольку оно обходит некоторые механизмы безопасности .NET.
<br>
### Как включить поддержку ключевого слова unsafe в проекте.
Примечание:
Мне не было необходимости использовать ключевое слово Unsafe, поэтому не знаю нужно ли выполнять все пункты для активации или достаточно только чего-то одного.
1. В Unity-проекте поставить галку напротив Allow ‘unsafe’ Code:
Edit -> Project Settings -> Player -> Allow ‘unsafe’ Code
(Можно просто забить в поиск в окне Project Settings слово «unsafe».
2. Создать обычный файл с расширением .rsp (например, csc.rsp) в папке, где находится скрипт с ключевым словом Unsafe или в корневой директории. Запишите в него всего одну строку "-unsafe" (без кавычек). Возможно, потребуется перезапустить Rider, чтобы применить настройки.
3. Если в Unity-проекте используется Assembly Definitions, то тогда в asmdef-файле нужно поставить галку напротив «Allow ‘unsafe’ Code»
### Как определить (пометить) «небезопасный» код.
В этом примере мы объявляем метод SquarePointer как unsafe, чтобы мы могли принимать указатель на float и разыменовывать его. Затем мы вызываем этот метод в unsafe блоке в Main, передавая адрес переменной a.
```csharp
unsafe static void SquarePointer(float* p)
{
*p *= *p;
}
static void Main()
{
float a = 5;
unsafe
{
SquarePointer(&a);
}
Console.WriteLine(a); // Выводит "25", так как 5^2 = 25
}
```
<br>
### Небезопасные функции и небезопасные операции
**Указатели (Pointers)**
Это переменные, которые хранят адреса памяти. Они используются для прямого управления памятью и для работы с данными на низком уровне.
```csharp
unsafe
{
int var = 20;
int* pVar = &var;
Console.WriteLine("Value of var: " + *pVar); // Выводит "Value of var: 20"
}
```
<br>
**Операторы адреса и разыменования (Address and Dereference Operators)**
Эти операторы (& и \*) используются для работы с указателями. Оператор & возвращает адрес переменной, а оператор * разыменовывает указатель, то есть возвращает данные по адресу, который хранится в указателе.
```csharp
unsafe
{
int var = 20;
int* pVar = &var;
*pVar = 10;
Console.WriteLine("Value of var: " + var); // Выводит "Value of var: 10"
}
```
<br>
**Небезопасные массивы (Unsafe Arrays)**
В небезопасном контексте можно получить прямой указатель на элементы массива и работать с ним как с непрерывным блоком памяти.
```csharp
unsafe
{
int[] array = new int[5] {1, 2, 3, 4, 5};
fixed (int* pArray = array)
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine(*(pArray + i)); // Выводит значения массива
}
}
}
```
<br>
**Структуры с фиксированным размером (Fixed Size Buffers)**
Это структуры, которые содержат массив фиксированного размера. Они могут быть полезны при взаимодействии с нативным кодом, который ожидает блок памяти фиксированного размера.
Обратите внимание, что код ниже не скомпилируется в C#, так как массивы фиксированного размера могут быть только членами структур, и их можно инициализировать только в небезопасном контексте. Это часто используется при взаимодействии с нативным кодом, но редко используется в обычном C# коде.
```csharp
unsafe struct FixedBuffer
{
public fixed int array[10];
}
unsafe
{
FixedBuffer buffer;
for (int i = 0; i < 10; i++)
{
buffer.array[i] = i;
}
}
```
<br>
**Стековые выделения (Stack Allocations)**
С помощью оператора stackalloc можно выделить блок памяти прямо на стеке.
Этот набор инструментов можно назвать "особенностями небезопасного кода" или "механизмами небезопасного программирования" в C#.
В этом примере мы используем stackalloc для выделения блока памяти на стеке, а затем используем эту память для хранения целых чисел от 0 до 99.
```csharp
unsafe
{
int* pBuffer = stackalloc int[100];
for (int i = 0; i < 100; i++)
{
pBuffer[i] = i;
}
}
```