C# in a Nutshell by
Get full access to C# in a Nutshell and 60K+ other titles, with a free 10-day trial of O’Reilly.
There are also live events, courses curated by job role, and more.
Synopsis
This is the value type used to store unmanaged pointers or handles (e.g., IntPtr objects are used in the System.IO.FileStream class to hold file handles).
Using this type allows your pointers to be platform-independent, as IntPtr is automatically mapped to a 32-bit integer on 32-bit operating systems and to a 64-bit integer on 64-bit operating systems. The IntPtr type is CLS-compliant and should be used in preference of the UIntPtr .
Get C# in a Nutshell now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.
Just what is an IntPtr exactly?
Through using IntelliSense and looking at other people’s code, I have come across this IntPtr type; every time it has needed to be used I have simply put null or IntPtr.Zero and found most functions to work. What exactly is it and when/why is it used?
8 Answers 8
It’s a «native (platform-specific) size integer.» It’s internally represented as void* but exposed as an integer. You can use it whenever you need to store an unmanaged pointer and don’t want to use unsafe code. IntPtr.Zero is effectively NULL (a null pointer).
It’s a value type large enough to store a memory address as used in native or unsafe code, but not directly usable as a memory address in safe managed code.
You can use IntPtr.Size to find out whether you’re running in a 32-bit or 64-bit process, as it will be 4 or 8 bytes respectively.
![]()
Here’s an example:
I’m writing a C# program that interfaces with a high-speed camera. The camera has its own driver that acquires images and loads them into the computer’s memory for me automatically.
So when I’m ready to bring the latest image into my program to work with, the camera driver provides me with an IntPtr to where the image is ALREADY stored in physical memory, so I don’t have to waste time/resources creating another block of memory to store an image that’s in memory already. The IntPtr just shows me where the image already is.
![]()
A direct interpretation
An IntPtr is an integer which is the same size as a pointer.
You can use IntPtr to store a pointer value in a non-pointer type. This feature is important in .NET since using pointers is highly error prone and therefore illegal in most contexts. By allowing the pointer value to be stored in a «safe» data type, plumbing between unsafe code segments may be implemented in safer high-level code — or even in a .NET language that doesn’t directly support pointers.
The size of IntPtr is platform-specific, but this detail rarely needs to be considered, since the system will automatically use the correct size.
The name «IntPtr» is confusing — something like Handle might have been more appropriate. My initial guess was that «IntPtr» was a pointer to an integer. The MSDN documentation of IntPtr goes into somewhat cryptic detail without ever providing much insight about the meaning of the name.
An alternative perspective
An IntPtr is a pointer with two limitations:
- It cannot be directly dereferenced
- It doesn’t know the type of the data that it points to.
In other words, an IntPtr is just like a void* — but with the extra feature that it can (but shouldn’t) be used for basic pointer arithmetic.
Intptr c что это
The IntPtr type is designed to be an implementation-sized pointer. An instance of this type is expected to be the size of a native int for the current implementation.
For more information on the native int type, see Partition II of the CLI Specification.
[ Note : The IntPtr type provides CLS-compliant pointer functionality.
IntPtr instances can also be used to hold handles.
The IntPtr type is CLS-compliant while the UIntPtr type is not. The UIntPtr type is provided mostly to maintain architectural symmetry with the IntPtr type.
]
.NET и работа с неуправляемым кодом. Часть 1
Сегодня я хочу показать один из способов работы с неуправляемым кодом, посредством специального класса Marshal. Большинство методов, определенных в этом классе, обычно используются разработчиками, которым нужно обеспечить сопряжение между моделями управляемого и неуправляемого программирования.
Маршалинг взаимодействия определяет, какие данные передаются в аргументах и возвращаемых значений методов между управляемой и неуправляемой памятью во время вызова. Маршалинг взаимодействия — это процесс времени выполнения, выполняемый службой маршалинга среды CLR.
Мне не хотелось бы полностью описывать всю структуру взаимодействия, т.к. это заняло бы значительную часть статьи. В этой статье я опишу принцип взаимодействия на конкретных примерах, опишу способы выделения и очистки выделенной памяти.
Для начала возьмём пример небольшой структуры, описанной в C и посмотрим, как сделать аналогичную структуру для C#.
struct test
<
struct innerstr
<
char str[300];
int Int;
int * in_pInt;
> in ;
char str[2][50];
int IntArr[10];
int * pInt;
innerstr* pStruct;
int * ptr;
>;* This source code was highlighted with Source Code Highlighter .
[StructLayout(LayoutKind.Sequential)]
public struct Test
<
public Innerstr _in;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50 * 2)]
public char [] str;;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public int [] IntArr;
public IntPtr pInt;
public IntPtr pStruct;
public IntPtr ptr;
[StructLayout(LayoutKind.Sequential)]
public struct Innerstr
<
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 300)]
internal string str;
public int _Int;
public IntPtr in_pInt;
>
>
* This source code was highlighted with Source Code Highlighter .
Как можете заметить, все указатели из C были заменения на тип IntPtr из C#. Двумерные массивы — на одномерные, аналогичной длины. А сама структура подписана аттрибутом [StructLayout]. Значение LayoutKind параметра Sequential используется для принудительного последовательного размещения членов в порядке их появления.
Для массивов необходимо указать их тип как UnmanagedType.ByValArray и сразу же указать их точный размер. Даже если размер самой переменной будет отличаться — при передаче, он автоматически будет уравнен в необходимый размер.
Вызов неуправляемого кода
extern «C» __declspec(dllexport) int ExpFunc(test* s, bool message)
* This source code was highlighted with Source Code Highlighter .
[ return :MarshalAs(UnmanagedType.I4)]
[DllImport( «TestTkzDLL.dll» )]
public static extern int ExpFunc([In, Out] IntPtr c, [In] bool message);
* This source code was highlighted with Source Code Highlighter .
Как вы наверное заметили, перед вызово необходимо сначало объявить все IntPtr. Для этого необходимо использовать примерно следующий код:
// для получения указателя на => int* pInt
int _pInt = 2010; // значение числа
IntPtr _pInt_buffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(_pInt)); // выделили кусочек памяти
Marshal.StructureToPtr(_pInt, _pInt_buffer, false ); // записали содержимое
test.pInt = _pInt_buffer; // сохранили
* This source code was highlighted with Source Code Highlighter .
По аналогии, и для innerstr* pStruct, и для всех остальных указателей.
Test.Innerstr inner2 = new Test.Innerstr();
IntPtr _pStruct_buffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(inner2));
Marshal.StructureToPtr(inner2, _pStruct_buffer, false );
test.pStruct = _pStruct_buffer;
* This source code was highlighted with Source Code Highlighter .
Вот и всё, всё просто. Теперь осталось из кода вызвать метод
/////////////////////////////////////// <br ?>
// ГЕНЕРИРУЕМ ЗАПРОС (способ с маршилингом данных в память, затем передачей ссылки)
/////////////////////////////////////
IntPtr ptr1 = Marshal.AllocCoTaskMem(Marshal.SizeOf(test));
Marshal.StructureToPtr(test, ptr1, false );
int retInt = ExpFunc(ptr1, false ); // вызов ветода
test = (StartClass.Test)Marshal.PtrToStructure(ptr1, typeof (StartClass.Test)); /// получаем наше значение обратно из неуправляемого кода
* This source code was highlighted with Source Code Highlighter .
В данном случае я перенес всю структуру в неуправляемую память, а затем передал ссылку на этот кусок, который затем в C был прочитан. Этого можно не делать, если передавать по ref, но я столкнулся с тем, что огромные структуры ref просто не мог перенести в неуправляемую память, а способ передавать ссылку работает всегда
Затем не забудьте почистить память. В отличие от управляемого кода, сборщик мусора не может чистить неуправляемый. Поэтому необходимо вызвать Marshal.FreeCoTaskMem(ptr); для всех ссылок IntPtr
PS: добавлено позже… аттрибут [StructLayout(LayoutKind.Sequential)], также может указывать на используемую таблицу символов, ANSI или UNICODE. Для этого необходимо написать [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)], [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] или [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]. По-умолчанию используется ANSI.
Ну вот и всё, на это первая часть статьи завершается. В следующей части я опишу, каким образом возможно использовать динамический размер массивом, как можно быстро преобразовать многомерные массивы в одномерные и наоборот, чтобы передавать в неуправляемый код, как организовать удобную для программиста структуру для прозрачной работы с маршалингом и некоторые другие
Обновлено
Добавлены исходники тестового проекта. Скачать