C# tutorials > Modern C# Features > C# 6.0 and Later > What are native sized integers (`nint`, `nuint`)?
What are native sized integers (`nint`, `nuint`)?
C# 9.0 introduced nint
and nuint
, which are native-sized integers. This means their size depends on the underlying platform's architecture (32-bit or 64-bit). Understanding these types is crucial for interoperability with native libraries and optimizing performance in certain scenarios.
Definition and Basic Usage
nint
represents a signed native-sized integer, and nuint
represents an unsigned native-sized integer. The sizeof
operator returns the size (in bytes) of the type. The size will be 4 bytes on a 32-bit platform and 8 bytes on a 64-bit platform. The example also shows how to check if your application is running on a 64-bit process.
using System;
public class NativeIntegersExample
{
public static void Main(string[] args)
{
nint nativeInt = 10;
nuint nativeUInt = 20;
Console.WriteLine($"Native Int: {nativeInt}");
Console.WriteLine($"Native UInt: {nativeUInt}");
Console.WriteLine($"Size of nint: {sizeof(nint)}");
Console.WriteLine($"Size of nuint: {sizeof(nuint)}");
// Check if the platform is 64-bit
if (Environment.Is64BitProcess)
{
Console.WriteLine("Running on a 64-bit process.");
}
else
{
Console.WriteLine("Running on a 32-bit process.");
}
}
}
Concepts Behind Native-Sized Integers
The primary purpose of nint
and nuint
is to interoperate with native APIs that use platform-specific integer sizes. Many native libraries use IntPtr
and UIntPtr
, which have been around since .NET 1.0. nint
and nuint
are designed to be CLS-compliant equivalents of IntPtr
and UIntPtr
respectively, providing better type safety and language integration.
Real-Life Use Case: Interoperability with Native Libraries
A common use case for native-sized integers is when you're interacting with unmanaged code via Platform Invoke (P/Invoke). In this example, we're using DllImport
to call the GetCurrentProcessId
function from kernel32.dll
. The return type is declared as nint
, ensuring it matches the platform's native integer size. This is a contrived example; in more complex cases the native code might expect an integer pointer. Without nint
and nuint
, you would need to use IntPtr and UIntPtr and potentially perform casts, reducing type safety.
// Example illustrating interaction with native code (P/Invoke)
using System;
using System.Runtime.InteropServices;
public class NativeInterop
{
[DllImport("kernel32.dll")]
public static extern nint GetCurrentProcessId();
public static void Main(string[] args)
{
nint processId = GetCurrentProcessId();
Console.WriteLine($"Current Process ID: {processId}");
}
}
When to Use Them
Use nint
and nuint
primarily when interacting with native libraries that rely on platform-specific integer sizes. They are also beneficial when working with large arrays or memory regions where the index needs to accommodate the maximum possible memory address size on the platform. They should be preferred over IntPtr
and UIntPtr
in new code. Don't use them as general-purpose integers; stick to int
, long
, etc., unless you have a specific reason to use native-sized integers.
Memory Footprint
The memory footprint of nint
and nuint
depends on the platform. On a 32-bit platform, they are 4 bytes, and on a 64-bit platform, they are 8 bytes. Be mindful of this when designing data structures, particularly when dealing with large collections. Using int
when a native-sized integer is not needed can save memory on 64-bit systems.
Alternatives
Before C# 9.0, the alternatives were IntPtr
and UIntPtr
. These types are still available, but nint
and nuint
are preferred due to better type safety and integration with the C# language. For general-purpose integers, int
, long
, uint
, and ulong
are the standard choices. If you don't need native sized integers stick with these standard types.
Pros
IntPtr
and UIntPtr
.
Cons
int
if not strictly necessary.
Best Practices
nint
and nuint
only when necessary for native interoperability or when dealing with memory addresses.
Interview Tip
When asked about nint
and nuint
in an interview, explain that they are native-sized integers introduced in C# 9.0 to improve interoperability with native libraries and provide better type safety than IntPtr
and UIntPtr
. Be sure to mention their platform-dependent size and the scenarios where they are most appropriate. Also, mention the memory footprint considerations.
FAQ
-
Are `nint` and `nuint` CLS-compliant?
Yes,
nint
andnuint
are CLS-compliant, which means they can be used in code that interoperates with other .NET languages. -
Can I use `nint` and `nuint` in mathematical operations?
Yes, you can use
nint
andnuint
in mathematical operations, but be mindful of potential overflow issues, especially when performing operations between native-sized integers and regular integers. -
How do `nint` and `nuint` relate to `IntPtr` and `UIntPtr`?
nint
andnuint
are CLS-compliant equivalents toIntPtr
andUIntPtr
. They offer better type safety and language integration and should be preferred in new code. The underlying representation is the same: a pointer sized integer that matches the target architecture.