Use the ref and out keyword on a pointer parameter - c#

I'm learning C and C#, this question is for C#. Why would you ever use the out and ref keywords on pointers? With pointers you have direct access to the variable. I found this code on msdn:here.
Here is the code:
static int value = 20;
public unsafe static void F(out int* pi1, ref int* pi2)
{
int i = 10;
pi1 = &i;
fixed (int* pj = &value)
{
// ...
pi2 = pj;
}
}

Why would you ever use the out and ref keywords on pointers?
Well, why would you ever use the out and ref keywords, period? You use the out keyword when you wish to call a method that modifies an existing variable. You use the ref keyword when you wish to call a method that reads and modifies an existing variable. That the variables are of pointer type seems to not be particularly relevant.
If your question is in fact "can you give me an example of realistic code in which you might want to pass a pointer-typed variable by ref?" then I must confess that in ten years of writing C# code I have never used pointers in production code and very rarely use ref, so I don't have an example from personal experience. I can imagine such a thing though. For example, imagine a traditional C-style doubly-linked list. You might have a situation where you want to both read and mutate the head and tail pointers of the list, and do so by passing ref Link*s to the head and tail.
Now that you have included the link to where you found this code I note that it explicitly says that this is an example of dangerously broken code that you must never write. Asking under what circumstances you would want to write such code is therefore a non-starter. I really don't understand the point of your question now that I see the origin of the code; you should never write code like this; that's the whole point of the sample.

Why would you ever use the out and ref keywords on pointers?
When you want to provide a pointer to the caller of your function, in the case of out, or when you want to be given a pointer and optionally modify it to point to something different, in the case of ref.
If you don't need to mutate the pointer, and instead only need to dereference the pointer to see what it is pointing to, then you can pass the pointer by value, rather than by reference, which is the behavior whenever out and ref are not used.

I've never used pointers in C#, but I do use ref parameters with reference types. Reason: clear intentions. If I see a method that takes a ref parameter, I know that this parameter will be mutated, so no surprises there.

Related

How does C#/.NET implement pinning of ref/in/out parameters?

In "unsafe" C# code, it is possible to get a pointer to a ref, in, or out parameter by using the fixed statement:
class A
{
unsafe void Test(ref int i)
{
fixed(int* ptr = &i)
{
// Do something with ptr.
}
}
}
The fixed statement "pins" the memory for i in place for the duration of the block so that the GC won't move the memory for i someplace else, which would invalidate ptr.
So my question, which I ask out of curiosity and a desire to better understand the performance implications of pinning ref/in/out parameters, is: How does C# and/or the .NET runtime know what object, if any, actually needs to be pinned? Because if i is a reference to a member field of an object, then doesn't it need to pin that whole object? And if i is a reference to a local variable in the calling function, then isn't there nothing that needs to be pinned at all? Does it somehow walk up the call stack until it finds the actual variable or field referred to by i? (Which sounds potentially expensive.)

Is it possible to create a 6400 byte integer?

I have a function which I can't alter because of protection and abstraction, and it is declared like this:
GetDeviceLongInfo(int, int, ref int);
In which the "ref int" argument to be passed is said to give back 6400 bytes of information.
My question is, how can I get this information in a variable if the only choice I have is to give the function an Int32? Can I allocate more memory for that Int32? Is this even possible to achieve in some way?
EDIT:
I can tell you that the function uses the ref int to dump values in it, the int size (size of the information) is not fixed, depends on the option chosed in the second parameter. I can't even look at the function to see how it uses that ref.
You can allocate an int[] and pass that to the function. This is a hack but I don't see why it should not be safe.
var array = new int[6400 / sizeof(int)];
GetDevice(..., ref array[0]);
The array is pinned by the CLR for the duration of the call.
Note, that ref is a so called managed pointer to the CLR. It is marshaled by passing it as a pointer and pinning the object it points to. An int[] would be passed in almost the same way (a pointer to the first element is passed).
Can I allocate more memory for that Int32? No
Is this even possible to achieve in some way? Changing the signature or using the int as a reference to the data are both options
You're attempting to marshal an array (which is a native pointer to data) to an integer. C# will have no problem with that, but processing it is another story. Also note that depending on your architecture you will have different pointer sizes, which means using a 32-bit int isn't the way to go.
See also: http://msdn.microsoft.com/en-us/library/z6cfh6e6(v=vs.110).aspx
I cannot remember the details from the top of my head, but basically you want to use the MarshalAs to tell .NET that it's a pointer to an array. IIRC it was something like this (1600 = 6400/4):
void GetDeviceLongInfo(int, int, [MarshalAs(UnmanagedType.LPArray, SizeConst=1600)] int[] ar );
update
I noticed the questions on how this works, so here it is... How this signature will work: signature in C is probably (long, long, long*) which means the third argument should be a pointer to int. The underlying buffer will be filled with the GetDeviceLongInfo by means of a strncpy or something similar. Things that can go wrong is passing a buffer that's too small (that's checked running it in Debug mode in VS), using the wrong processor architecture, incorrectly passing the integer instead of a pointer (you can try casting the address of your AllocHGlobal to int and see if that works -- that does mean you will have to run on x86 though) and basically a whole lot of other things :-)
Apparently you cannot change anything to the signature. What you're basically attempting to do then is allocate a buffer, cast it to an int* and then process it. Since the approach of usr isn't working, I'd try Marshal.AllocHGlobal to create the buffer, and then pass it to the function (if needed, use unsafe code).

Is it safe to keep C++ pointers in C#?

I'm currently working on some C#/C++ code which makes use of invoke. In the C++ side there is a std::vector full of pointers each identified by index from the C# code, for example a function declaration would look like this:
void SetName(char* name, int idx)
But now I'm thinking, since I'm working with pointers couldn't I sent to C# the pointer address itself then in code I could do something like this:
void SetName(char*name, int ptr)
{
((TypeName*)ptr)->name = name;
}
Obviously that's a quick version of what I'm getting at (and probably won't compile).
Would the pointer address be guaranteed to stay constant in C++ such that I can safely store its address in C# or would this be too unstable or dangerous for some reason?
In C#, you don't need to use a pointer here, you can just use a plain C# string.
[DllImport(...)]
extern void SetName(string name, int id);
This works because the default behavior of strings in p/invoke is to use MarshalAs(UnmanagedType.LPStr), which converts to a C-style char*. You can mark each argument in the C# declaration explicitly if it requires some other way of being marshalled, eg, [MarshalAs(UnmanagedType.LPWStr)], for an arg that uses a 2-byte per character string.
The only reason to use pointers is if you need to retain access to the data pointed to after you've called the function. Even then, you can use out parameters most of the time.
You can p/invoke basically anything without requiring pointers at all (and thus without requiring unsafe code, which requires privileged execution in some environments).
Yes, no problem. Native memory allocations never move so storing the pointer in an IntPtr on the C# side is fine. You need some kind of pinvoked function that returns this pointer, then
[DllImport("something.dll", CharSet = CharSet.Ansi)]
void SetName(IntPtr vector, string name, int index);
Which intentionally lies about this C++ function:
void SetName(std::vector<std::string>* vect, const char* name, int index) {
std::string copy = name;
(*vect)[index] = copy;
}
Note the usage of new in the C++ code, you have to copy the string. The passed name argument points to a buffer allocated by the pinvoke marshaller and is only valid for the duration of the function body. Your original code cannot work. If you intend to return pointers to vector<> elements then be very careful. A vector re-allocates its internal array when you add elements. Such a returned pointer will then become invalid and you'll corrupt the heap when you use it later. The exact same thing happens with a C# List<> but without the risk of dangling pointers.
I think it's stable till you command C++ code and perfectly aware what he does, and other developers that work on the same code know about that danger too.
So by my opinion, it's not very secure way of architecture, and I would avoid it as much as I can.
Regards.
The C# GC moves things, but the C++ heap does not move anything- a pointer to an allocated object is guaranteed to remain valid until you delete it. The best architecture for this situation is just to send the pointer to C# as an IntPtr and then take it back in C++.
It's certainly a vastly, incredibly better idea than the incredibly BAD, HORRIFIC integer cast you've got going there.

C++ to C# port question: How would I deal with a method that has a double* as a parameter?

I'm porting a C++ library to C# and I've encountered some methods that have double* pointers as parameters. What's the best way to deal with this? Perhaps modify the calling code so that it's not passing pointers? I WOULD just wrap the code in an "unsafe" block and set the compiler's /unsafe flag, but I can't do that inside of the method signature.
Maybe uusing ref (or out) on parameters may be good enough, or if you need to handle an array of those use a double[].
Maybe post the method definition so that it gets clearer what you really need.
I'm assuming that you wish to use managed safe code
Depends on how the pointer is used. If it's used as an array inside your method then you'll need to pass an array to the method and therefor need to change the signature.
if it's used as a double and (re)assigned it again depends. Does the method have return type? if so using ref double might be the way to go. if the method doesn't have a return type return the value being assigned and let the caller passing to a local instead of passing by ref.
if the double* is used as a double and never assign simply pass as double.
Probably it translates to ref double or out double or double[]. Which it should be depends on the semantics of the code. C++ double* can actually mean a number of things.
It's highly unlikely that unsafe code is needed.
You could mark the function as unsafe and compile with the /unsafe flag:
private static unsafe void MyFunction(double *d)
See http://msdn.microsoft.com/en-us/library/chfa2zb8.aspx
Where you are passing pointers, you are simply changing the default pass-by-value mechanism to pass-by-reference, in which case, use the ref keyword:
public void SomeMethod(ref double val) { }
In which you need to ensure you specifiy ref when call it too:
SomeMethod(ref 12.0);
What you do will depend on how the pointer is being used. If the pointer is there so that the calling code can pass an array of doubles, then have the method accept a double[]. If the pointer is there so that the called code can modify the value of a double variable from the caller, then you have two choices:
Modify the semantics of the call in such a way that the double is a return value (this would be the way I'd suggest)
Declare the parameter as ref or out (depending on whether or not you want to guarantee that the called function will assign a value.
Don't just throw unsafe blocks around code so that you can continue to use pointers; unsafe should be used very sparingly (ideally not at all).
It depends on how the function uses the pointer. You don't really give enough info to give a solid answer, but I'll give it a shot anyway.
Normal C# code
If the code in the method is de-referencing the pointer and assigning a value, without doing any pointer arithmetic, then simply make the parameter an out parameter.
If the previous paragraph is true, and you don't already have a return value, simply modify the signature of the method to return a double.
If the code is not doing pointer arithmetic, but uses the value that already exists at the pointed location, as well as assigning it, then make the parameter a ref parameter.
If the code does no pointer arithmetic, uses the value, but doesn't assign it, then you should probably change it from a pointer to a plain double, and not make it ref or out.
If the implementation of the function is doing pointer arithmetic, then you'll need to build and pass some sort of indexable collection, such as one that implements IList or an array.
Alternatives to normal C# code
You could always opt to mark your code unsafe, too, and use pointers. That will probably be a lot more work than simple logical translations, but is more likely to maintain a similar performance profile.
You could also opt to use C++/CLI instead of C#. It is also a .Net langauge, and might be simpler (depending on your app) to integrate directly with the existing C++ code.

Are ref and out in C# the same a pointers in C++?

I just made a Swap routine in C# like this:
static void Swap(ref int x, ref int y)
{
int temp = x;
x = y;
y = temp;
}
It does the same thing that this C++ code does:
void swap(int *d1, int *d2)
{
int temp=*d1;
*d1=*d2;
*d2=temp;
}
So are the ref and out keywords like pointers for C# without using unsafe code?
They're more limited. You can say ++ on a pointer, but not on a ref or out.
EDIT Some confusion in the comments, so to be absolutely clear: the point here is to compare with the capabilities of pointers. You can't perform the same operation as ptr++ on a ref/out, i.e. make it address an adjacent location in memory. It's true (but irrelevant here) that you can perform the equivalent of (*ptr)++, but that would be to compare it with the capabilities of values, not pointers.
It's a safe bet that they are internally just pointers, because the stack doesn't get moved and C# is carefully organised so that ref and out always refer to an active region of the stack.
EDIT To be absolutely clear again (if it wasn't already clear from the example below), the point here is not that ref/out can only point to the stack. It's that when it points to the stack, it is guaranteed by the language rules not to become a dangling pointer. This guarantee is necessary (and relevant/interesting here) because the stack just discards information in accordance with method call exits, with no checks to ensure that any referrers still exist.
Conversely when ref/out refers to objects in the GC heap it's no surprise that those objects are able to be kept alive as long as necessary: the GC heap is designed precisely for the purpose of retaining objects for any length of time required by their referrers, and provides pinning (see example below) to support situations where the object must not be moved by GC compacting.
If you ever play with interop in unsafe code, you will find that ref is very closely related to pointers. For example, if a COM interface is declared like this:
HRESULT Write(BYTE *pBuffer, UINT size);
The interop assembly will turn it into this:
void Write(ref byte pBuffer, uint size);
And you can do this to call it (I believe the COM interop stuff takes care of pinning the array):
byte[] b = new byte[1000];
obj.Write(ref b[0], b.Length);
In other words, ref to the first byte gets you access to all of it; it's apparently a pointer to the first byte.
Reference parameters in C# can be used to replace one use of pointers, yes. But not all.
Another common use for pointers is as a means for iterating over an array. Out/ref parameters can not do that, so no, they are not "the same as pointers".
ref and out are only used with function arguments to signify that the argument is to be passed by reference instead of value. In this sense, yes, they are somewhat like pointers in C++ (more like references actually). Read more about it in this article.
The nice thing about using out is that you're guaranteed that the item will be assigned a value -- you will get a compile error if not.
Actually, I'd compare them to C++ references rather than pointers. Pointers, in C++ and C, are a more general concept, and references will do what you want.
All of these are undoubtedly pointers under the covers, of course.
While comparisons are in the eye of the beholder...I say no. 'ref' changes the calling convention but not the type of the parameters. In your C++ example, d1 and d2 are of type int*. In C# they are still Int32's, they just happen to be passed by reference instead of by value.
By the way, your C++ code doesn't really swap its inputs in the traditional sense. Generalizing it like so:
template<typename T>
void swap(T *d1, T *d2)
{
T temp = *d1;
*d1 = *d2;
*d2 = temp;
}
...won't work unless all types T have copy constructors, and even then will be much more inefficient than swapping pointers.
The short answer is Yes (similar functionality, but not exactly the same mechanism).
As a side note, if you use FxCop to analyse your code, using out and ref will result in a "Microsoft.Design" error of "CA1045:DoNotPassTypesByReference."

Categories