Skip to content

Commit 41110bd

Browse files
authored
Update intro sections
1 parent 7f30eb5 commit 41110bd

File tree

1 file changed

+50
-26
lines changed

1 file changed

+50
-26
lines changed

docs/csharp/language-reference/unsafe-code.md

Lines changed: 50 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
2-
title: "Unsafe code, pointers to data, and function pointers"
2+
title: "Unsafe code"
33
description: Learn about unsafe code, pointers, and function pointers. C# requires you to declare an unsafe context to use these features to directly manipulate memory or function pointers (unmanaged delegates).
4-
ms.date: 02/06/2025
4+
ms.date: 07/07/2025
55
f1_keywords:
66
- "functionPointer_CSharpKeyword"
77
helpviewer_keywords:
@@ -13,41 +13,66 @@ helpviewer_keywords:
1313
- "C# language, pointers"
1414
- "pointers [C#], about pointers"
1515
---
16-
# Unsafe code, pointer types, and function pointers
1716

18-
Most of the C# code you write is "verifiably safe code." *Verifiably safe code* means .NET tools can verify that the code is safe. In general, safe code doesn't directly access memory using pointers. It also doesn't allocate raw memory. It creates managed objects instead.
17+
# Unsafe code
1918

20-
C# supports an [`unsafe`](keywords/unsafe.md) context, in which you can write *unverifiable* code. In an `unsafe` context, code can use pointers, allocate and free blocks of memory, and call methods using function pointers. Unsafe code in C# isn't necessarily dangerous; it's just code whose safety can't be verified.
19+
Unsafe code is a dialect of C# that unlocks powerful capabilities often needed for interoperability with native libraries, high-performance algorithms, and other low-level programming needs. However, these capabilities bypass C#'s usual safety checks, placing the responsibility for correctness squarely on the unsafe code author. Mistakes in unsafe code can lead to bugs like buffer overruns and use-after-free errors. To help isolate risks, unsafe code must appear within an [`unsafe`](keywords/unsafe.md) context, keeping it clearly separated from regular safe code and making it easier to audit.
2120

22-
Unsafe code has the following properties:
21+
In contrast, most C# code is safe code. Safe code always accesses, uses, and releases memory in ways that are proven correct by the C# compiler and .NET runtime.
2322

24-
- Methods, types, and code blocks can be defined as unsafe.
25-
- In some cases, unsafe code can increase an application's performance by removing array bounds checks.
26-
- Unsafe code is required when you call native functions that require pointers.
23+
Within an `unsafe` context, you can use pointers, manually allocate and free blocks of memory, and call methods through function pointers.
24+
25+
Unsafe code has the following characteristics:
26+
27+
- Methods, types, and code blocks can be marked as unsafe.
28+
- Removing array bounds checks in unsafe code can, in some cases, improve performance.
29+
- Unsafe code is required for calling native functions that use pointers.
2730
- Using unsafe code introduces security and stability risks.
28-
- The code that contains unsafe blocks must be compiled with the [**AllowUnsafeBlocks**](compiler-options/language.md#allowunsafeblocks) compiler option.
31+
- Code containing unsafe blocks must be compiled with the [`AllowUnsafeBlocks`](compiler-options/language.md#allowunsafeblocks) compiler option.
2932

3033
## Pointer types
3134

32-
In an unsafe context, a type can be a pointer type, in addition to a value type, or a reference type. A pointer type declaration takes one of the following forms:
35+
In an unsafe context, a type can be a pointer type, in addition to a value type, or a reference type. A pointer type declaration takes the following forms (with the `*` being the key syntax difference):
3336

3437
``` csharp
3538
type* identifier;
36-
void* identifier; //allowed but not recommended
3739
```
3840

39-
The type specified before the `*` in a pointer type is called the **referent type**.
40-
41-
Pointer types don't inherit from [object](builtin-types/reference-types.md) and no conversions exist between pointer types and `object`. Also, boxing and unboxing don't support pointers. However, you can convert between different pointer types and between pointer types and integral types.
41+
The pointer indirection operator `*` can be used to access the contents at the location pointed to by the pointer variable. For example, consider the following declaration:
4242

43-
When you declare multiple pointers in the same declaration, you write the asterisk (`*`) together with the underlying type only. It isn't used as a prefix to each pointer name. For example:
43+
The following example demonstrates a complete example of using pointer types.
4444

4545
```csharp
46-
int* p1, p2, p3; // Ok
47-
int *p1, *p2, *p3; // Invalid in C#
46+
int number = 42;
47+
int numberAgain = 0;
48+
bool same = false;
49+
50+
unsafe
51+
{
52+
int* pointer = &number; // Assigns the address of number
53+
numberAgain = *pointer; // Retrieves the value at that address (42)
54+
same = number == numberAgain; // Will resolve to true
55+
Console.WriteLine($"Pointer (address): {(ulong)pointer}; Pointer value: {*pointer}");
56+
}
57+
58+
Console.WriteLine($"NumberAgain: {numberAgain}; Same: {same}");
59+
60+
/* Example output (pointer address will vary each run):
61+
Pointer (address): 6127673188; Pointer value: 42
62+
NumberAgain: 42; Same: True
63+
*/
4864
```
4965

50-
The garbage collector doesn't keep track of whether an object is being pointed to by any pointer types. If the referrant is an object in the managed heap (including local variables captured by lambda expressions or anonymous delegates), the object must be [pinned](./statements/fixed.md) for as long as the pointer is used.
66+
The example also demonstrates how safe and unsafe code can interact. The first call to `Console.WriteLine` must be within the unsafe block because `pointer` can only be used in the `unsafe` context given its `int*` definition.
67+
68+
### Defining pointer types
69+
70+
When you declare multiple pointers in the same declaration, you write the asterisk (`*`) together with the underlying type only. For example:
71+
72+
```csharp
73+
int* p1, p2, p3; // Ok
74+
int *p1, *p2, *p3; // Invalid
75+
```
5176

5277
The value of the pointer variable of type `MyType*` is the address of a variable of type `MyType`. The following are examples of pointer type declarations:
5378

@@ -57,18 +82,17 @@ The value of the pointer variable of type `MyType*` is the address of a variable
5782
- `char* p`: `p` is a pointer to a char.
5883
- `void* p`: `p` is a pointer to an unknown type.
5984

60-
The pointer indirection operator `*` can be used to access the contents at the location pointed to by the pointer variable. For example, consider the following declaration:
61-
62-
```csharp
63-
int* myVariable;
64-
```
65-
66-
The expression `*myVariable` denotes the `int` variable found at the address contained in `myVariable`.
6785

6886
There are several examples of pointers in the articles on the [`fixed` statement](statements/fixed.md). The following example uses the `unsafe` keyword and the `fixed` statement, and shows how to increment an interior pointer. You can paste this code into the Main function of a console application to run it. These examples must be compiled with the [**AllowUnsafeBlocks**](compiler-options/language.md#allowunsafeblocks) compiler option set.
6987

7088
:::code language="csharp" source="snippets/unsafe-code/FixedKeywordExamples.cs" ID="5":::
7189

90+
### Using pointer types
91+
92+
Pointer types don't inherit from [object](builtin-types/reference-types.md) and no conversions exist between pointer types and `object`. Also, boxing and unboxing don't support pointers. However, you can convert between different pointer types and between pointer types and integral types.
93+
94+
The garbage collector doesn't keep track of whether an object is being pointed to by any pointer types. If the referrant is an object in the managed heap (including local variables captured by lambda expressions or anonymous delegates), the object must be [pinned](./statements/fixed.md) for as long as the pointer is used.
95+
7296
You can't apply the indirection operator to a pointer of type `void*`. However, you can use a cast to convert a void pointer to any other pointer type, and vice versa.
7397

7498
A pointer can be `null`. Applying the indirection operator to a null pointer causes an implementation-defined behavior.

0 commit comments

Comments
 (0)