7

i have a function which is called from a library in C++ that has been imported to a C# project

I think it is asking for a pointer to an array. But I'm not sure how to make it work.

here is what it is asking for function(float*, float*);

but if i do something like

float[] f = {};
float[] f1 = {};

function(f,f1);

it says there are invalid arguments.

user1395152
  • 355
  • 2
  • 4
  • 13
  • 5
    I am confused - why have you used the [tag:c#] tag? Did you mean to use [tag:c++]? – Oded Mar 13 '13 at 20:57
  • Possible duplicate http://stackoverflow.com/questions/2546706/pointers-in-c-sharp-to-make-int-array – Aaron Blenkush Mar 13 '13 at 20:57
  • 1
    It is a C++ Library being Imported into C# – user1395152 Mar 13 '13 at 20:57
  • 2
    Pointer types *are* supported in C#. Why is everyone confused? – Triynko Mar 13 '13 at 20:58
  • Can you post the complete function prototype you are trying to import please? i.e. copy/paste the C++ version from the header file. EDIT: also, a brief explanation of what *should* go into the function would be good. float* is just a pointer to a float and that could be anything in C/C++... – Roman Gruber Mar 13 '13 at 20:59
  • 1
    It is considered "unsafe", since C# is a managed language. – Aaron Blenkush Mar 13 '13 at 20:59
  • @Triynko, in unsafe mode and with pinned memory, yes. Unsafe mode is called unsafe for a reason, and pinned memory cannot be moved by heap compaction. – Frédéric Hamidi Mar 13 '13 at 20:59
  • @Triynko - because the question text doesn't explain the C# connection in any way and form. – Oded Mar 13 '13 at 21:00
  • I used pointers all the time, especially on ridiculously large chunks of memory that aren't going to be moved around anyway. It can significantly speed up certain calculations. – Triynko Mar 13 '13 at 21:01
  • @user1395152 it's just interop, you have to DllImport that function so **please show that prototype (in C#)**. You can marshal them as **IntPtr** or **float[]** but you instruct the compiler how to do it in the C# prototype (where you have the DllImport attribute) – Adriano Repetti Mar 13 '13 at 21:01
  • @Oded, the question says "What does float* mean as a type in C#". It's a float pointer. Very clear. – Triynko Mar 13 '13 at 21:02
  • @Triynko, but... I don't understand. If you do that, why use C# instead of C++ in the first place? – Frédéric Hamidi Mar 13 '13 at 21:02
  • @Frédéric, because the C# memory management is useful in 99% of the rest of the application logic? I'm just saying, for certain things, pointers are great. I was just confused about why people were confused why someone asked what a float pointer was in C#. – Triynko Mar 13 '13 at 21:04
  • The relevant question here is *what is the callee doing with the pointer*? Is it (1) filling in a single float into the variable? (2) testing the pointer for null? (3) reading a float out of the variable and writing another one in? (4) doing array accesses/pointer manipulation to read other variables? (5) something else? Without knowing whether its an array or not and whether it is read-only, read-write or write-only it is very hard to say what the right thing to do is. – Eric Lippert Mar 13 '13 at 23:00

5 Answers5

4

float * is a float pointer type in C#.

If the function is expecting float pointer arguments (float *), then the function must be presumed to work on pointers, possibly involving pointer arithmetic. It is therefore important to preserve that signature.

To pass float arrays in C# as float pointers (float*), you need to pin/fix the arrays in memory in an unsafe context to acquire a pointer to them that you can pass to the function to preserve its functionality:

unsafe
{
    fixed (float* ptr_f = f) //or equivalently "... = &f[0]" address of f[0]
    fixed (float* ptr_f2 = f2) //or equivalently "... = &f2[0]" address of f2[0]
    {
        function( ptr_f, ptr_f2 );
    }
}

You will also need to mark your assembly as unsafe (in project properties > build tab > allow unsafe code checkbox).

Triynko
  • 18,766
  • 21
  • 107
  • 173
  • to be clear... preserving the signature requires the least changes to the code, but if you want to avoid an unsafe context and inefficient memory pinning, just convert the float pointer (float*) parameters to the safer float array (float[]) parameter type and check the function's logic to ensure there is no pointer arithmetic such as f++ or f+=4 or dereferencing like (*(f + 4)). If the float pointers are accessed by array index like f[i], then the syntax is identical in C# for accessing an array and it's just a stylistic difference, see http://stackoverflow.com/q/1790704/88409 – Triynko Mar 13 '13 at 21:34
3

If this is a method imported via DLLImport() you can simply replace the array pointers with the typed array.

So a signature:

[DLLImport("some.dll")]
SomeMethod(int* a, float* b)

Becomes

[DLLImport("some.dll")]
SomeMethod(int[] a, float[] b)

Please note that this assumes the original c/c++ method was expecting an array. This won't work if the pointers are not intended to reference arrays.

FlyingStreudel
  • 4,434
  • 4
  • 33
  • 55
  • Upvote. I answered too, assuming the OP was importing source code into a C# project (wasn't very clear), but if it is a p-invoke call... this works for simple types. The CLR will automatically pin references to managed arrays for the duration of the function call (although beware of functions that try to cache the managed pointers): http://stackoverflow.com/a/2218540/88409. – Triynko Mar 13 '13 at 22:19
  • More attention needs to be paid to the marshalling of complex types like strings, structures, and multidimentional arrays, such as whether the marshalling requires copying to and/or from unmanaged memory and whether any conversion is necessary (e.g. from unicode to ANSI strings). It depends on whether the type is "blittable" and whether you specify attributes on the parameters like MarshalAs, In, or Out (or imply In or Out attributes by using the "out" or "ref" keywords). See: http://msdn.microsoft.com/en-us/library/23acw07k.aspx and http://msdn.microsoft.com/en-us/magazine/cc164193.aspx. – Triynko Mar 13 '13 at 22:21
1

You need to know exactly what the invoked C++ function is expecting.

In C (and C++) all of these function signatures are for all intents and purposes exactly the same:

void foo( float *x   , float *y   ) ;
void foo( float *x   , float  y[] ) ;
void foo( float  x[] , float *y   ) ;
void foo( float  x[] , float  y[] ) ;

All of them take 2 arguments, each of which contains is a pointer to (contains the address of) a variable of type float. And all of these expressions are exactly identical in C/C++:

float x[] ;
float *y  ;

float r1 = *(x+37) ; // all evaluate to the zero-relative
float r2 = x[37]   ; // 37th element of the array.
float r3 = *(y+37) ;
float r4 = y[37]   ;
  • The expression *x says, "Fetch the float (4 bytes) located at the address contained in x.
  • The expression *(x+n), where n is an integer value, says "Take the address contained in x, and to that add the offset in bytes obtained by the expression sizeof(float) * n. Fetch the float value located at the resulting address.
  • The array expression x[n] is exactly equivalent to the pointer expression *(x+n).

And since arrays in C/C++ do not have any associated metadata describing their size, you need to know exactly what the called function is expecting.

Commonly, one passes a pointer (call by reference) in order to allow the caller to de-reference the point and set a value for you — the equivalent of C#'s ref and out keywords:

float x ;
float y ;
Foo( ref x , ref y ) ; // the callee MAY, but is not REQUIRED to set a value before returning to the caller.
Bar( out x , out y ) ; // the callee MUST set a value before returning to the caller.

The idiom your function is using is always used to locate an array, though typically, one also passes a size:

void foo( float *array , int array_length ) ;

Although is it not unusual, if the function is expecting the array to be a list of non-zero numeric values to be something like a C-style, NUL-terminated string. Given the function signature, for instance:

float compute_mean( float *Xs ) ;

It's not unusual for it to be expected to be invoked thus:

float Xs[] = { 3.0 , 2.5 , 9.8 , 7,5 , 0 , } ;
float mean = compute_mean( Xs ) ;

and the definition to be something like:

float compute_mean( float *Xs )
{
  float n   = 0.0 ;
  float sum = 0.0 ;
  float mean ;
  while ( *p )
  {
    ++n ;
    sum += *p++ ;
  }
  mean = n > 0 ? sum / n : 0.0 ;
  return mean ;
}

So you need to know the semantics of the method you're invoking.

Hope this helps.

Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135
0

that does not work at all in C#, when importing C / C++ libraries in C# you should use IntPtr instead of float*, see here for some examples: float* from C to C#

Community
  • 1
  • 1
Davide Piras
  • 43,984
  • 10
  • 98
  • 147
0

It is asking for a float pointer, (The machine address of a point in memory that contains an IEEE Floating point value.) C# does not allow managed use of pointers, so you will need to construct an IntPtr variable and pass that to the C++ function.

NOTE: Just because it is called IntPtr doesn't mean it is only a pointer to Integers. The Int is because all pointers are integers. It can be a pointer to anything.

Charles Bretana
  • 143,358
  • 22
  • 150
  • 216
  • 2
    C# doesn't allow managed used of pointers? You can use them in managed (unsafe) code and you can even pass them to unmanaged DllImported functions... – Adriano Repetti Mar 13 '13 at 21:04