Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert optional pointer argument from C++ code to C#

I have function in c++ something like this:

// C++
bool Foo(int* retVal = NULL)
{
    // ...
    if (retVal != NULL)
        *retVal = 5;
    // ...
    return true;
}

And I can use functions in two ways:

int ret;
Foo(&ret);

Foo();

When I write code in C# I used ref keyword:

// C#
bool Foo(ref int retVal = null)
{
    // ...
    if (retVal != null)
    {
        retVal = 5;
    }
    // ...
    return true;
}

but compiler said:

A ref or out parameter cannot have a default value.

How can I solve this problem?

like image 415
marbel82 Avatar asked Jun 26 '15 13:06

marbel82


People also ask

What is the use of pointer as argument in C?

Pointers as Argument in C programming language. Pointers as arguments can read/change the values of the variables that are pointed at. In other words we can say that through pointer as an argument we can modify the values of actual arguments of calling function.

Can a pointer be converted to another type in C?

The venerable book “ The C Programming Language ” by Brian Kernighan and Dennies Ritchie has this to say on pointer conversions: A pointer to one type may be converted to a pointer to another type. The resulting pointer may cause addressing exceptions if the subject pointer does not refer to an object suitably aligned in storage.

How do you pass a pointer to a function in C?

Example: Passing Pointer to a Function in C Programming. In this example, we are passing a pointer to a function. When we pass a pointer as an argument instead of a variable then the address of the variable is passed instead of the value. So any change made by the function using the pointer is permanently made at the address of passed variable.

How to pass a pointer as an argument instead of a variable?

Lets take an example to understand how this is done. In this example, we are passing a pointer to a function. When we pass a pointer as an argument instead of a variable then the address of the variable is passed instead of the value. So any change made by the function using the pointer is permanently made at the address of passed variable.


3 Answers

The simplest way would be to just write an overload:

bool Foo()
{
    int notUsed;
    return Foo(ref notUsed);
}

bool Foo(ref int retVal)
{
    // ...
    retVal = 5;
    // ...
    return true;
}

If you actually need to know whether the ref value is needed, well, you can still use pointers, but you'll need an unsafe context:

unsafe bool Foo()
{
    return Foo(null);
}

unsafe bool Foo(ref int retVal)
{
    return Foo(&retVal);
}

private unsafe bool Foo(int* retVal)
{
    // ...
    if (retVal != null)
    {
        *retVal = 5;
    }
    // ...
    return true;
}

Or, without unsafe as suggested in the comments, as pointers in C# may be considered as heavy artillery:

bool Foo()
{
    var notNeeded = 0;
    return Foo(ref notNeeded, false);
}

bool Foo(ref int retVal)
{
    return Foo(ref retVal, true);
}

private bool Foo(ref int retVal, bool retValNeeded)
{
    // ...
    if (retValNeeded)
    {
        retVal = 5;
    }
    // ...
    return true;
}
like image 93
Lucas Trzesniewski Avatar answered Oct 06 '22 19:10

Lucas Trzesniewski


The ref of C# is more similar to the & (reference) of C++ than to the * of C and C++ (pointer). As C++ references, they must reference something.

Now, you could:

public class OptionalRef<T>
{
    public T Value { get; set; }

    public static implicit operator OptionalRef<T>(T value)
    {
        return new OptionalRef<T> { Value = value };
    }

    public static implicit operator T(OptionalRef<T> optional)
    {
        return optional.Value;
    }

    public override string ToString()
    {
        return Value != null ? Value.ToString() : null;
    }
}

then

static bool Foo(OptionalRef<int> retVal = null)
{
    // ...
    if (retVal != null)
    {
        retVal.Value = 5;
    }
    // ...
    return true;
}

and you use it like:

Foo(); // null passed
Foo(null); // same

Foo(5); // not interested if the value is changed

// Full use
OptionalRef<int> val = 5;
Foo(val);
int ret = val;

note that I'm not fully endorsing the semantics I wrote

It is more a case of you asked for something, I gave you something, no questions asked

like image 3
xanatos Avatar answered Oct 06 '22 20:10

xanatos


I'd go about this one of two ways. If you REALLY want to have a reference to your object you can wrap that in a class. Those are always passed by reference so you'll get your modification the way you want and you can instantiate it to null.

Here is an example.

public class HolderObject
{
    public string myStr {get; set;}
}
public class Program
{

    public static void Main()
    {    
        var xyz = new HolderObject() {
            myStr = "1234"
        };
        Console.WriteLine(xyz.myStr);
        FixString(xyz);
        Console.WriteLine(xyz.myStr);
        FixString();
        Console.WriteLine(xyz.myStr);


    }

    private static bool FixString(HolderObject input = null)
    {
        if (input != null)
            input.myStr = "test";
        return true;
    }
}

prints

1234
test

Another solution is to overload your function.

bool Foo()
{        
    // ...
    return true;
}

bool Foo(ref int retVal = null)
{
    // ...
    if (retVal != null)
    {
        retVal = 5;
    }
    return Foo();
}

I REALLY don't like this. I'm actually in the middle of working on code in C# that has been pulled directly from C++. Functions that are nested 6 or 7 layers deep modifying an object that was passed by reference. That is hard to read and if you look at the code analysis warnings, it will suggest you don't use ref values.

If you can I'd move away from passing by ref as much as possible and return the value back that has been modified. Or pass an object back that contains both your bool and your new value.

like image 2
thinklarge Avatar answered Oct 06 '22 20:10

thinklarge