13

I have a struct in c++:

struct some_struct{
uchar* data;
size_t size;
}

I want to pass it between manged(c#) and native(c++). What is the equivalent of size_t in C# ?

P.S. I need an exact match in the size because any byte difference will results in huge problem while wrapping

EDIT:

Both native and manged code are under my full control ( I can edit whatever I want)

Humam Helfawi
  • 19,566
  • 15
  • 85
  • 160
  • that question solve the problem by giving an alternative way to declare an array. So it does not answer my question, – Humam Helfawi Oct 02 '15 at 12:06
  • Are you actually asking [this](http://stackoverflow.com/q/4956435/1997232) question? – Sinatr Oct 02 '15 at 12:08
  • no the reserve one :)... I could try all c# numeric type and get the best one but I do not think it is the right way – Humam Helfawi Oct 02 '15 at 12:10
  • 2
    [.NET equivalent of size_t](http://stackoverflow.com/questions/772531/net-equivalent-of-size-t) in C# is IntPtr or UIntPtr for 64bit. – Black Frog Oct 02 '15 at 12:11
  • 2
    That answer is wrong. The correct answer is that the c# equivalent is UIntPtr. It's 32-bit on 32-bit platforms, 64-bit on 64-bit platforms, and unsigned. I can't post it as an answer because this question has been marked as a duplicate. – Roger Sanders Oct 02 '15 at 12:11
  • Please my question is not duplicate. – Humam Helfawi Oct 02 '15 at 12:12
  • 1
    I think there is no straight way. Arrays in C# are indexed by int which is hard defined to 32 bits. Arrays cannot be bigger than 4 Gig elements (bytes? dunno). You'll have to fiddle with finding out the OS and architecture and make a best guess. It also means that you'll have to call different functions for interfacing with the native code, possibly choosing at run time. – Peter - Reinstate Monica Oct 02 '15 at 12:13
  • @RogerSanders There is no guarantee that the native code uses 64 bit ints just because it's running on a 64 bit platform! I run 32 bit programs all the time, and I bet you they use 32 bit size_t. – Peter - Reinstate Monica Oct 02 '15 at 12:14
  • @Peter Schneider He's passing data between c# and C++ through interop, that means his architecture has to match. If his c++ code is compiled as 64-bit, size_t will be 64-bit, as will UIntPtr. If his c++ code is compiled as 32-bit, size_t will be 32-bit, as will UIntPtr. If the architecture of his c# and c++ code was mismatched, he wouldn't be able to load the modules into the same process anyway. – Roger Sanders Oct 02 '15 at 12:16
  • 1
    @BlackFrog I know that your answer has been given elsewhere but I do not think it's correct. The [U]IntPtr types in C# are ints which can hold the value of a *pointer* (which is typically 64 bits on a 64 bit architecture). But that may theoretically well be different from size_t which is an int *value* type used as an index or array size. An implementation may choose to stay with 32 bit ints (and not allow arrays > 2 Gig), for example because the CPU has 64 bit addresses but 32 bit ints. – Peter - Reinstate Monica Oct 02 '15 at 12:19
  • @RogerSanders I cannot interop with a 32bit DLL from a 64 bit app? (I really don't know.) – Peter - Reinstate Monica Oct 02 '15 at 12:21
  • Do you necessarily need to have `size` as `size_t`? Just use the biggest unsigned integer number you may need. See [this](http://stackoverflow.com/a/131833/1997232) answer. – Sinatr Oct 02 '15 at 12:22
  • @Peter Schneider No, you can't. You can't even load it into the same process. Not as code anyway. – Roger Sanders Oct 02 '15 at 12:22
  • 1
    Also, size_t is technically completely implementation defined, as you point out. That would mean that it's theoretically impossible to marshal in a truly platform independent manner. Interop is an inherently practical real-world issue though, and has to deal with real-world realities. The real world reality here is, that for any implementation you care to name, size_t is an integer which is equivalent in size to the pointer type. – Roger Sanders Oct 02 '15 at 12:23
  • So could the solution be just to define size as some big type that is known to all language and use it?... any sugestion about this type ? – Humam Helfawi Oct 02 '15 at 12:26
  • To the close voters: I think indeed that the question is different from the one cited in the reason to close. The OP here really needs the type size which was not necessary in the other question, and so the answers there do not answer the OP's problem. – Peter - Reinstate Monica Oct 02 '15 at 12:27
  • 1
    I reopened the question, since the chosen duplicate wasn't particularly good IMO. Also, [cppreference](http://en.cppreference.com/w/cpp/types/size_t) says: "On many platforms (an exception are systems with segmented addressing) `std::size_t` can safely store the value of any non-member pointer, in which case it is synonymous with `std::uintptr_t`." – Lucas Trzesniewski Oct 02 '15 at 12:30
  • 1
    Humam, I think after what @Roger said that he's right (UIntPtr should do the job). That said, the situation is easier if both the native and the managed code are under your control. Then you can just use an integer type of sufficient and equal width, most likely 32 bit (that is in C#, uint; in C++ uint32_t). – Peter - Reinstate Monica Oct 02 '15 at 12:35
  • 1
    There's a lot of Sturm und Drang here, but the first and foremost consideration when you have to interop with unmanaged code is *practicality*. And that struct declaration gives you no lack of headaches as-is, it is as unpractical as you could possibly ever make it. You are doomed to have to use IntPtr to ever actually ever do anything useful with it, for both members, casting just adds more impracticality. – Hans Passant Oct 02 '15 at 13:38

3 Answers3

15

There is no C# equivalent to size_t.

The C# sizeof() operator always returns an int value regardless of platform, so technically the C# equivalent of size_t is int, but that's no help to you.

(Note that Marshal.SizeOf() also returns an int.)

Also note that no C# object can be larger than 2GB in size as far as sizeof() and Marshal.Sizeof() is concerned. Arrays can be larger than 2GB, but you cannot use sizeof() or Marshal.SizeOf() with arrays.

For your purposes, you will need to know what the version of code in the DLL uses for size_t and use the appropriate size integral type in C#.

One important thing to realise is that in C/C++ size_t will generally have the same number of bits as intptr_t but this is NOT guaranteed, especially for segmented architectures.

I know lots of people say "use UIntPtr", and that will normally work, but it's not GUARANTEED to be correct.


From the C/C++ definition of size_t, size_t

is the unsigned integer type of the result of the sizeof operator;

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
  • From a language functionality point of view, I'd say you're correct. From an interop point of view, the types are clearly not equivalent though. What if the OP wants to round-trip the original type back to C++? There clearly could be data loss. – Roger Sanders Oct 02 '15 at 12:37
  • How does `size_t` and `sizeof()` relates? – ST3 Oct 02 '15 at 12:37
  • OP wants to use a `struct` which contains a `size_t` field for interop. [cppreference](http://en.cppreference.com/w/cpp/types/size_t) defines it as `typedef /*implementation-defined*/ size_t;` - so the true answer depends on the used C++ implementation. – Lucas Trzesniewski Oct 02 '15 at 12:38
  • According to your edit, if `foo()` returns `size_t` in C++ and `foo()` returns `Byte` in C#, OP should use `Byte`. Doesn't make sense for me. – ST3 Oct 02 '15 at 12:42
  • @ST3 `size_t` in C/C++ matches the C/C++ `sizeof()` return type. It does not have an equivalent in C#. But your comment "if foo() returns size_t in C++ and foo() returns Byte" doesn't make sense. How can `foo()` return `Byte` AND `size_t`? – Matthew Watson Oct 02 '15 at 12:43
  • This seems to be the correct answer regardless of what other users had said about UIntPtr usage. For the viewsize SIZE_T parameter of NtMapViewOfSection function, IntPtr or UIntPtr only works on a x64 process and the NTSTATUS error code is clear, its a invalid parameter. If I use UInteger instead, it works as expected for both x86 and x64. – ElektroStudios Apr 14 '19 at 08:13
7

The best equivalent for size_t in C# is the UIntPtr type. It's 32-bit on 32-bit platforms, 64-bit on 64-bit platforms, and unsigned.

Roger Sanders
  • 2,232
  • 1
  • 22
  • 29
  • Watch out. `size_t` is not guaranteed to be the same as `sizeof(void*)` for all implementations of C/C++. – Matthew Watson Oct 02 '15 at 12:51
  • @MatthewWatson I believe you mean that `sizeof(size_t)` is not guaranteed to be the same as `sizeof(void*)`. `size_t` is the result of the `sizeof` operator (as you stated in another comment), but that doesn't mean that `size_t` has sufficient range to store any possible `void*`'s value. – monkey0506 Nov 18 '19 at 23:24
  • 1
    That's what most people are looking for instead of a pedantic "There isn't a strict equivalent". – Aykhan Hagverdili Sep 05 '20 at 11:08
5

You better to use nint/nuint which is wrapper around IntPtr/UIntPtr

Timur Vafin
  • 113
  • 1
  • 6
  • 1
    In 2022, this is the right answer. `UIntPtr` works, but `nuint` is much better. It's treated more like an integer instead of a struct, so much less explicit casting required. – caesay Aug 01 '22 at 16:59