Passing jagged array byte[][] to unmanaged code

G

Guest

Hi Gurus,

I need to transfer a jagged array of byte[][] by reference to unmanaged
function, The unmanaged code should changed the values of the array, and when
the unmanaged function returns I need to show the array data to the end user.

Can I do that?
How?
 
N

Nicholas Paldino [.NET/C# MVP]

Sharon,

You are going to have to marshal this manually, as I don't think there
is a mechanism in the framework to handle this on your own.

You would have to iterate through each array of arrays, dynamically
allocating the memory in unmanaged memory, then copying the values. On
return, you would have to copy the values back.

Unsafe code would help a little bit here, as you wouldn't have to worry
about allocating and deallocating the memory (you could use stackalloc to
allocate the memory for you).
 
G

Guest

I'm afraid this kind of work will undermine the performance as there is a lot
of data to copy.
I thought there is a way to use the managed array by reference on the
unmanaged side and avoiding the memory copy.
If there is no solution for that, I think I will write some more piece of
code in native C++ (unmanaged) to do that.
 
W

Willy Denoyette [MVP]

Sharon said:
I'm afraid this kind of work will undermine the performance as there is a
lot
of data to copy.
I thought there is a way to use the managed array by reference on the
unmanaged side and avoiding the memory copy.
If there is no solution for that, I think I will write some more piece of
code in native C++ (unmanaged) to do that.



What make you think that copying will be an issue? How large are these
array's? And why are you using an jagged array, while this kind of type
can't be handled directly in C or C++ in the first place?

Willy.
 
B

Ben Voigt [C++ MVP]

Willy Denoyette said:
What make you think that copying will be an issue? How large are these
array's? And why are you using an jagged array, while this kind of type
can't be handled directly in C or C++ in the first place?

C++, native as well as managed, handle jagged arrays just fine. But
unmanaged C++ can't directly handle .NET arrays of anything but fundamental
types, which includes .NET jagged arrays.

Why not change the C++ code in question to C++/CLI, then you can use the
jagged .NET array directly?

This poster also previously asked the same question on the C++ list (or
maybe it was interop), and got the same answers there.
 
G

Guest

The data maybe be large as several giga bytes. and the data copy will be done
when moving it to the unmanaged code and once more when getting it back.

I'm getting a lot of System.Array that encapsulates a byte[] from a COM
component, so I thought to put this arrays (without copying) in a jagged
array of byte[][], and then letting another native C++ (unmanaged) DLL change
this jagged array for me for later use. This native C++ DLL is doing some
heavy algorithm and therefore is written in C++ and not .NET.

The original data that is read from a COM component to a managed code is
used for display and other stuff before it's moved to the C++ DLL (unmanaged
algorithm component). So I have the data in a managed memory, and should be
changed by an unmanaged code and back to the managed code.

How can I do it effectively regarding performance and development time.
Simple and effective ???
 
G

Guest

I also believe that the best solution will be something like that.
I think that I will write an additional CLI/C++ component that will be used
as a bridge between the unmanaged code and the managed code.
 
W

Willy Denoyette [MVP]

Sharon said:
The data maybe be large as several giga bytes. and the data copy will be
done
when moving it to the unmanaged code and once more when getting it back.

Hmmm.... Several Gigabytes? Is this running on a 64-bit OS?
I'm getting a lot of System.Array that encapsulates a byte[] from a COM
component, so I thought to put this arrays (without copying) in a jagged
array of byte[][], and then letting another native C++ (unmanaged) DLL
change
this jagged array for me for later use. This native C++ DLL is doing some
heavy algorithm and therefore is written in C++ and not .NET.

Why a jagged array?
The original data that is read from a COM component to a managed code is
used for display and other stuff before it's moved to the C++ DLL
(unmanaged
algorithm component). So I have the data in a managed memory, and should
be
changed by an unmanaged code and back to the managed code.

How can I do it effectively regarding performance and development time.
Simple and effective ???


So, you are getting arrays of bytes from COM, which means that you are
already copying from native memory to managed memory. Also, the COM array is
not jagged, so why are you putting this data in a jagged array? Why not pass
the CLR byte array to C++ and let the C++ function change the array contents
without copying?

Willy.
 
W

Willy Denoyette [MVP]

Ben Voigt said:
C++, native as well as managed, handle jagged arrays just fine. But
unmanaged C++ can't directly handle .NET arrays of anything but
fundamental types, which includes .NET jagged arrays.
Note that I said "this kind of type can't be handled directly in C and C++",
we are talking about C# here which implies "managed array types".
Why not change the C++ code in question to C++/CLI, then you can use the
jagged .NET array directly?

Maybe the OP can change the C++ code to C++/CLI, maybe he doesn't own the
source, or is not willing to introduce yet another language in his code
base.
This poster also previously asked the same question on the C++ list (or
maybe it was interop), and got the same answers there.
He also asked the same question several times before, and clearly said that
the "algorithm" was written by another group and had to be in unmanaged
code.

Willy.
 
B

Ben Voigt [C++ MVP]

Willy Denoyette said:
Sharon said:
The data maybe be large as several giga bytes. and the data copy will be
done
when moving it to the unmanaged code and once more when getting it back.

Hmmm.... Several Gigabytes? Is this running on a 64-bit OS?
I'm getting a lot of System.Array that encapsulates a byte[] from a COM
component, so I thought to put this arrays (without copying) in a jagged
array of byte[][], and then letting another native C++ (unmanaged) DLL
change
this jagged array for me for later use. This native C++ DLL is doing some
heavy algorithm and therefore is written in C++ and not .NET.

Why a jagged array?

Simply an array of arrays. Jagged, because each member array can have a
different size.

Stop receiving the COM array into a .NET array. Store each SAFEARRAY* as an
element in an array of IntPtr instead. Then give that IntPtr array to the
unmanaged code.
So, you are getting arrays of bytes from COM, which means that you are
already copying from native memory to managed memory. Also, the COM array
is not jagged, so why are you putting this data in a jagged array? Why not
pass

Each incoming array is one-dimensional, apparently. Knowing what jagged
means helps here.
the CLR byte array to C++ and let the C++ function change the array
contents without copying?

If the arrays coming from COM are allocated scattered throughout memory,
then it can't be passed as a single native array. It will have to be an
array of pointers.
 
W

Willy Denoyette [MVP]

Ben Voigt said:
Willy Denoyette said:
Sharon said:
The data maybe be large as several giga bytes. and the data copy will be
done
when moving it to the unmanaged code and once more when getting it back.

Hmmm.... Several Gigabytes? Is this running on a 64-bit OS?
I'm getting a lot of System.Array that encapsulates a byte[] from a COM
component, so I thought to put this arrays (without copying) in a jagged
array of byte[][], and then letting another native C++ (unmanaged) DLL
change
this jagged array for me for later use. This native C++ DLL is doing
some
heavy algorithm and therefore is written in C++ and not .NET.

Why a jagged array?

Simply an array of arrays. Jagged, because each member array can have a
different size.

I know what a managed jagged array is, you can not pass such type from C#
(or any other managed code) to C++ , even if you could, C++ cannot directly
access *managed* jagged arrays, it has no idea how they are laid out in
memory.

Stop receiving the COM array into a .NET array. Store each SAFEARRAY* as
an element in an array of IntPtr instead. Then give that IntPtr array to
the unmanaged code.


Each incoming array is one-dimensional, apparently. Knowing what jagged
means helps here.
Again, I know what a *managed* jagged array is, it's a type that is not know
by C++.
If the arrays coming from COM are allocated scattered throughout memory,
then it can't be passed as a single native array. It will have to be an
array of pointers.

In the OP's case, the array that comes from COM is a one-dimentional byte
array, as such it gets marshaled as a one-dimentional managed array, so COM
is a non issue here.

What the OP can do is store the address of each individual array in an array
of IntPtr and pass that array to C++ together with an array that defines the
size of each array pointed to by the pointers in the array of pointers, and
a third parameter that defines the size of the array of pointers, but that
's not the same as passing a jagged array.

The signature could look something like this:

[DllImport("blabala")]
static extern Foo(IntPtr[] ptr, int[] sizeOfElem, int elem);

however, this is not possible:

[DllImport("blabala")]
static extern Foo(byte[][] ptr);

See what I mean?

Willy.
 
B

Ben Voigt [C++ MVP]

Willy Denoyette said:
Ben Voigt said:
Willy Denoyette said:
The data maybe be large as several giga bytes. and the data copy will
be done
when moving it to the unmanaged code and once more when getting it
back.


Hmmm.... Several Gigabytes? Is this running on a 64-bit OS?

I'm getting a lot of System.Array that encapsulates a byte[] from a COM
component, so I thought to put this arrays (without copying) in a
jagged
array of byte[][], and then letting another native C++ (unmanaged) DLL
change
this jagged array for me for later use. This native C++ DLL is doing
some
heavy algorithm and therefore is written in C++ and not .NET.


Why a jagged array?

Simply an array of arrays. Jagged, because each member array can have a
different size.

I know what a managed jagged array is, you can not pass such type from C#
(or any other managed code) to C++ , even if you could, C++ cannot
directly access *managed* jagged arrays, it has no idea how they are laid
out in memory.

Stop receiving the COM array into a .NET array. Store each SAFEARRAY* as
an element in an array of IntPtr instead. Then give that IntPtr array to
the unmanaged code.


Each incoming array is one-dimensional, apparently. Knowing what jagged
means helps here.
Again, I know what a *managed* jagged array is, it's a type that is not
know by C++.
If the arrays coming from COM are allocated scattered throughout memory,
then it can't be passed as a single native array. It will have to be an
array of pointers.

In the OP's case, the array that comes from COM is a one-dimentional byte
array, as such it gets marshaled as a one-dimentional managed array, so
COM is a non issue here.

What the OP can do is store the address of each individual array in an
array of IntPtr and pass that array to C++ together with an array that
defines the size of each array pointed to by the pointers in the array of
pointers, and a third parameter that defines the size of the array of
pointers, but that 's not the same as passing a jagged array.

That *is* a jagged array. Any array of arrays is a jagged array, all
languages support the concept. P/Invoke cannot pass an array of
non-fundamental types and a .NET array is not a fundamental type. So native
C++ can't use a managed jagged array.
The signature could look something like this:

[DllImport("blabala")]
static extern Foo(IntPtr[] ptr, int[] sizeOfElem, int elem);

That is a native jagged array being passed. Now, instead of unmarshalling
the data from SAFEARRAY to a .NET array, and using Marshal to make a copy in
HGLOBAL memory, why not just store the SAFEARRAY* in the array, if the data
is just going to be passed back to unmanaged code?
however, this is not possible:

[DllImport("blabala")]
static extern Foo(byte[][] ptr);

See what I mean?

Willy.
 
W

Willy Denoyette [MVP]

Ben Voigt said:
Willy Denoyette said:
Ben Voigt said:
The data maybe be large as several giga bytes. and the data copy will
be done
when moving it to the unmanaged code and once more when getting it
back.


Hmmm.... Several Gigabytes? Is this running on a 64-bit OS?

I'm getting a lot of System.Array that encapsulates a byte[] from a
COM
component, so I thought to put this arrays (without copying) in a
jagged
array of byte[][], and then letting another native C++ (unmanaged) DLL
change
this jagged array for me for later use. This native C++ DLL is doing
some
heavy algorithm and therefore is written in C++ and not .NET.


Why a jagged array?

Simply an array of arrays. Jagged, because each member array can have a
different size.

I know what a managed jagged array is, you can not pass such type from C#
(or any other managed code) to C++ , even if you could, C++ cannot
directly access *managed* jagged arrays, it has no idea how they are laid
out in memory.

The original data that is read from a COM component to a managed code
is
used for display and other stuff before it's moved to the C++ DLL
(unmanaged
algorithm component). So I have the data in a managed memory, and
should be
changed by an unmanaged code and back to the managed code.

How can I do it effectively regarding performance and development
time.
Simple and effective ???

Stop receiving the COM array into a .NET array. Store each SAFEARRAY*
as an element in an array of IntPtr instead. Then give that IntPtr
array to the unmanaged code.



So, you are getting arrays of bytes from COM, which means that you are
already copying from native memory to managed memory. Also, the COM
array is not jagged, so why are you putting this data in a jagged
array? Why not pass

Each incoming array is one-dimensional, apparently. Knowing what jagged
means helps here.
Again, I know what a *managed* jagged array is, it's a type that is not
know by C++.
the CLR byte array to C++ and let the C++ function change the array
contents without copying?

If the arrays coming from COM are allocated scattered throughout memory,
then it can't be passed as a single native array. It will have to be an
array of pointers.

In the OP's case, the array that comes from COM is a one-dimentional byte
array, as such it gets marshaled as a one-dimentional managed array, so
COM is a non issue here.

What the OP can do is store the address of each individual array in an
array of IntPtr and pass that array to C++ together with an array that
defines the size of each array pointed to by the pointers in the array of
pointers, and a third parameter that defines the size of the array of
pointers, but that 's not the same as passing a jagged array.

That *is* a jagged array. Any array of arrays is a jagged array, all
languages support the concept. P/Invoke cannot pass an array of
non-fundamental types and a .NET array is not a fundamental type. So
native C++ can't use a managed jagged array.

When I'm talking of jagged arrays I'm referring to an array type defined in
the CLI (CLR), I don't know if the C or C++ standard has a definition for
"jagged arrays", but "jagged arrays" on the CLR, are arrays of arrays,
right, but the constituent arrays don't need to be of the same size.

For instance the following illustrates how you can define and access a
jagged array of int C#:
int jagged [][] = new int[][]{
new int[]{1, 2, 3, 4},
new int[]{4, 5, 6}
};
jagged[0][2] = 100;
jagged[1][2] = 5;
...
how you can you define and access such an array type in C/C++, note I'm not
asking for an array of pointers.

The signature could look something like this:

[DllImport("blabala")]
static extern Foo(IntPtr[] ptr, int[] sizeOfElem, int elem);

That is a native jagged array being passed.
How that?, the first argument is an array of IntPtr, marshaled as an array
of pointers, or do you mean that what is passed collectively defines an
array of arrays.

Now, instead of unmarshalling
the data from SAFEARRAY to a .NET array, and using Marshal to make a copy
in HGLOBAL memory, why not just store the SAFEARRAY* in the array, if the
data is just going to be passed back to unmanaged code?

I didn't say he should make a copy to "unmanaged" memory, I said he could
take the address of each individualy array store it in an array of IntPtr
(or void*) and pass that array to C++, something like this:

[DllImport("blabla.dll"), SuppressUnmanagedCodeSecurity] extern static
void Foo(IntPtr[] ia, int[] elems, int size);
...
// say jagged is an array that holds the marshaled COM arrays (be it
conforming or SAFEARRAY's is not the issue)
byte[][] jagged = new byte[][];
jagged[0] = CallCOM(); // returns an array of bytes.
jagged[1] = .......
.....
unsafe
{
IntPtr[] ptrArray = new IntPtr[jagged.Length];
int[] elems = new int[jagged.Length];
for(int n = 0; n < jagged.Length; n++)
{
fixed(byte* p = &jagged[n][0])
{
ptrArray[n] = new IntPtr(p);
elems[n] = jagged[n].Length;
}
}
Foo(ptrArray, elems, jagged.Length); // call "native code" that
changes the contents of jagged ... inline...
}
....

Willy.
 
B

Ben Voigt [C++ MVP]

Willy Denoyette said:
Ben Voigt said:
Willy Denoyette said:
The data maybe be large as several giga bytes. and the data copy will
be done
when moving it to the unmanaged code and once more when getting it
back.


Hmmm.... Several Gigabytes? Is this running on a 64-bit OS?

I'm getting a lot of System.Array that encapsulates a byte[] from a
COM
component, so I thought to put this arrays (without copying) in a
jagged
array of byte[][], and then letting another native C++ (unmanaged)
DLL change
this jagged array for me for later use. This native C++ DLL is doing
some
heavy algorithm and therefore is written in C++ and not .NET.


Why a jagged array?

Simply an array of arrays. Jagged, because each member array can have
a different size.


I know what a managed jagged array is, you can not pass such type from
C# (or any other managed code) to C++ , even if you could, C++ cannot
directly access *managed* jagged arrays, it has no idea how they are
laid out in memory.



The original data that is read from a COM component to a managed code
is
used for display and other stuff before it's moved to the C++ DLL
(unmanaged
algorithm component). So I have the data in a managed memory, and
should be
changed by an unmanaged code and back to the managed code.

How can I do it effectively regarding performance and development
time.
Simple and effective ???

Stop receiving the COM array into a .NET array. Store each SAFEARRAY*
as an element in an array of IntPtr instead. Then give that IntPtr
array to the unmanaged code.



So, you are getting arrays of bytes from COM, which means that you are
already copying from native memory to managed memory. Also, the COM
array is not jagged, so why are you putting this data in a jagged
array? Why not pass

Each incoming array is one-dimensional, apparently. Knowing what
jagged means helps here.

Again, I know what a *managed* jagged array is, it's a type that is not
know by C++.

the CLR byte array to C++ and let the C++ function change the array
contents without copying?

If the arrays coming from COM are allocated scattered throughout
memory, then it can't be passed as a single native array. It will have
to be an array of pointers.


In the OP's case, the array that comes from COM is a one-dimentional
byte array, as such it gets marshaled as a one-dimentional managed
array, so COM is a non issue here.

What the OP can do is store the address of each individual array in an
array of IntPtr and pass that array to C++ together with an array that
defines the size of each array pointed to by the pointers in the array
of pointers, and a third parameter that defines the size of the array
of pointers, but that 's not the same as passing a jagged array.

That *is* a jagged array. Any array of arrays is a jagged array, all
languages support the concept. P/Invoke cannot pass an array of
non-fundamental types and a .NET array is not a fundamental type. So
native C++ can't use a managed jagged array.

When I'm talking of jagged arrays I'm referring to an array type defined
in the CLI (CLR), I don't know if the C or C++ standard has a definition
for "jagged arrays", but "jagged arrays" on the CLR, are arrays of arrays,
right, but the constituent arrays don't need to be of the same size.

For instance the following illustrates how you can define and access a
jagged array of int C#:
int jagged [][] = new int[][]{
new int[]{1, 2, 3, 4},
new int[]{4, 5, 6}
};
jagged[0][2] = 100;
jagged[1][2] = 5;
...
how you can you define and access such an array type in C/C++, note I'm
not asking for an array of pointers.

In C++, arrays and pointers are interchangable (except for sizeof), so an
array of pointers is an array of arrays. You can of course have an array
object which combines the pointer and the length information, so a C++
jagged array could also look like: std::vector said:
The signature could look something like this:

[DllImport("blabala")]
static extern Foo(IntPtr[] ptr, int[] sizeOfElem, int elem);

That is a native jagged array being passed.
How that?, the first argument is an array of IntPtr, marshaled as an array
of pointers, or do you mean that what is passed collectively defines an
array of arrays.

Now, instead of unmarshalling
the data from SAFEARRAY to a .NET array, and using Marshal to make a copy
in HGLOBAL memory, why not just store the SAFEARRAY* in the array, if the
data is just going to be passed back to unmanaged code?

I didn't say he should make a copy to "unmanaged" memory, I said he could
take the address of each individualy array store it in an array of IntPtr
(or void*) and pass that array to C++, something like this:

[DllImport("blabla.dll"), SuppressUnmanagedCodeSecurity] extern static
void Foo(IntPtr[] ia, int[] elems, int size);
...
// say jagged is an array that holds the marshaled COM arrays (be it
conforming or SAFEARRAY's is not the issue)
byte[][] jagged = new byte[][];
jagged[0] = CallCOM(); // returns an array of bytes.
jagged[1] = .......
.....
unsafe
{
IntPtr[] ptrArray = new IntPtr[jagged.Length];
int[] elems = new int[jagged.Length];
for(int n = 0; n < jagged.Length; n++)
{
fixed(byte* p = &jagged[n][0])
{
ptrArray[n] = new IntPtr(p);
elems[n] = jagged[n].Length;
}
}
Foo(ptrArray, elems, jagged.Length); // call "native code" that
changes the contents of jagged ... inline...
}
...

Willy.
 
W

Willy Denoyette [MVP]

Ben Voigt said:
Willy Denoyette said:
Ben Voigt said:
The data maybe be large as several giga bytes. and the data copy
will be done
when moving it to the unmanaged code and once more when getting it
back.


Hmmm.... Several Gigabytes? Is this running on a 64-bit OS?

I'm getting a lot of System.Array that encapsulates a byte[] from a
COM
component, so I thought to put this arrays (without copying) in a
jagged
array of byte[][], and then letting another native C++ (unmanaged)
DLL change
this jagged array for me for later use. This native C++ DLL is doing
some
heavy algorithm and therefore is written in C++ and not .NET.


Why a jagged array?

Simply an array of arrays. Jagged, because each member array can have
a different size.


I know what a managed jagged array is, you can not pass such type from
C# (or any other managed code) to C++ , even if you could, C++ cannot
directly access *managed* jagged arrays, it has no idea how they are
laid out in memory.



The original data that is read from a COM component to a managed
code is
used for display and other stuff before it's moved to the C++ DLL
(unmanaged
algorithm component). So I have the data in a managed memory, and
should be
changed by an unmanaged code and back to the managed code.

How can I do it effectively regarding performance and development
time.
Simple and effective ???

Stop receiving the COM array into a .NET array. Store each SAFEARRAY*
as an element in an array of IntPtr instead. Then give that IntPtr
array to the unmanaged code.



So, you are getting arrays of bytes from COM, which means that you
are already copying from native memory to managed memory. Also, the
COM array is not jagged, so why are you putting this data in a jagged
array? Why not pass

Each incoming array is one-dimensional, apparently. Knowing what
jagged means helps here.

Again, I know what a *managed* jagged array is, it's a type that is not
know by C++.

the CLR byte array to C++ and let the C++ function change the array
contents without copying?

If the arrays coming from COM are allocated scattered throughout
memory, then it can't be passed as a single native array. It will
have to be an array of pointers.


In the OP's case, the array that comes from COM is a one-dimentional
byte array, as such it gets marshaled as a one-dimentional managed
array, so COM is a non issue here.

What the OP can do is store the address of each individual array in an
array of IntPtr and pass that array to C++ together with an array that
defines the size of each array pointed to by the pointers in the array
of pointers, and a third parameter that defines the size of the array
of pointers, but that 's not the same as passing a jagged array.

That *is* a jagged array. Any array of arrays is a jagged array, all
languages support the concept. P/Invoke cannot pass an array of
non-fundamental types and a .NET array is not a fundamental type. So
native C++ can't use a managed jagged array.

When I'm talking of jagged arrays I'm referring to an array type defined
in the CLI (CLR), I don't know if the C or C++ standard has a definition
for "jagged arrays", but "jagged arrays" on the CLR, are arrays of
arrays, right, but the constituent arrays don't need to be of the same
size.

For instance the following illustrates how you can define and access a
jagged array of int C#:
int jagged [][] = new int[][]{
new int[]{1, 2, 3, 4},
new int[]{4, 5, 6}
};
jagged[0][2] = 100;
jagged[1][2] = 5;
...
how you can you define and access such an array type in C/C++, note I'm
not asking for an array of pointers.

In C++, arrays and pointers are interchangable (except for sizeof), so an
array of pointers is an array of arrays. You can of course have an array
object which combines the pointer and the length information, so a C++
jagged array could also look like: std::vector<std::vector<int>*>


I expected this :).
It's not because you can "construct" something that looks and behaves like a
"jagged" array in C++ that they are the same as managed "jagged arrays", a
"jagged array" is a well defined language feature in .NET (all managed
languages including C++/CLI) with well defined language syntax rules and
based on a CLS compliant type from the CTS, and this is not true in C++.
in C#
int[3][] ja;
ja is a jagged array.

which is not possible in C++
int ja[3][];
will not compile.....
and
int ja[3][5];

is a two dimentional rectangular array, an array of arrays, but it's not a
jagged array!

Anyway, what's important here and what the OP is after, is that they can be
passed and accessed *directly* across the managed/unmanaged language (here
C# and C++) boundaries *without* the need to resort to some kind of custom
marshaling (like I've illustrated), and we both know that this is not the
case, right?

Willy.
 
B

Ben Voigt [C++ MVP]

I expected this :).
It's not because you can "construct" something that looks and behaves like
a "jagged" array in C++ that they are the same as managed "jagged arrays",
a "jagged array" is a well defined language feature in .NET (all managed

No, it's not. It's composition of two features: an array is an object, and
having arrays of objects.
languages including C++/CLI) with well defined language syntax rules and

Then what is the syntax for a managed jagged array in C++/CLI? Oh, it's
something like:

cli::array said:
based on a CLS compliant type from the CTS, and this is not true in C++.
in C#
int[3][] ja;
ja is a jagged array.

which is not possible in C++
int ja[3][];

The omitted dimension syntax is accepted in C and C++, but means something
entirely different. And I think it is the first dimension omitted, not the
last.
will not compile.....
and
int ja[3][5];

is a two dimentional rectangular array, an array of arrays, but it's not a
jagged array!

No, it's not an array of arrays at all. It is a single array, and can be
treated interchangeable as a 3x5 array, a 5x3 array, or a 15 element
one-dimensional array.

int ja1[5], ja2[5], ja3[5];
int* ja[] = { ja1, ja2, ja3 };

is an array of arrays.

Or, if you want to nitpick that this is an array of pointers,

int (&ja[])[5] = { ja1, ja2, ja3 };

Which is an array of arrays, but cannot be jagged.
Anyway, what's important here and what the OP is after, is that they can
be passed and accessed *directly* across the managed/unmanaged language
(here C# and C++) boundaries *without* the need to resort to some kind of
custom marshaling (like I've illustrated), and we both know that this is
not the case, right?

P/invoke can't handle arrays of ref class types, and an array is a ref
class, so no, p/invoke can't do an array of arrays (or array of lists, or
list of arrays, or array of strings, or ...). Jagged arrays aren't a
special case in any sense.
 
W

Willy Denoyette [MVP]

Ben Voigt said:
No, it's not. It's composition of two features: an array is an object,
and having arrays of objects.

Are you telling me that "jagged arrays" are not a .NET language concept
based on a well defined type in the type system and the CLR (CLI)?

The element type and shape of an array—including whether it is *jagged* or
*rectangular*, and the number of dimensions it has—are part of its type.
That why I keep saying that the declaration int[][] declares a distinct well
know array type!

Consider following snippets:

[1] An array of objects having an arrays of objects having an arrays of...
object[] oa = new object[2];
object[] oaa = new object[4];
oa[0] = oaa; // oa is an array of objects of array of objects
// Obviously the following is not possible, oa is not a jagged array
// oa[0][0] = new byte[4] {0, 2, 4, 6}; // NOT possible
// Following is OK.
oaa[0] = new byte[4] {0, 2, 4, 6};

Here 'oa' Defines an System.Object[] with Rank = 1, holding 2 elements of
element type CLASS (ELEMENT_TYPE_CLASS to be precise),
element oa[0] holds a System.Object[] with Rank = 1, holding 4 elements of
element type is CLASS (ELEMENT_TYPE_CLASS),
element oaa[0] Defines an System.Byte[] with Rank = 1, holding 4 elements of
element type Byte(ELEMENT_TYPE_BYTE)

[2]
string[] sa = new string[2];
sa[0] = "somestring";
Here 'sa' defines an System.String[] with Rank = 1, holding 4 elements of
element type CLASS (ELEMENT_TYPE_CLASS)

[3]

byte[,] nonJagged = new byte[4,5];
nonJagged[0,0] = 100;
nonJagged[1,1] = 200;
Here 'sa' defines an System.Byte[] with Rank = 2, holding 20 elements of
element type Byte(ELEMENT_TYPE_BYTE)
Notice Rank=2, This is a multi-dimentional rectangular array.

[4]

byte[][][] jagged = new byte[4][][];
jagged[0] = new byte[1][] {
new byte[4] {1, 2, 3, 4}};
jagged[1] ....

Here 'jagged' defines an System.Byte[][][] with Rank = 1, holding 4 elements
of element type SZARRAY(ELEMENT_TYPE_SZARRAY),
jagged[0] defines an System.Byte[][] with Rank = 1, holding 1 elements of
element type SZARRAY(ELEMENT_TYPE_SZARRAY)
and the element jagged[0] holds a reference to a
System.Byte[] with Rank = 1, holding 4 elements of element type
Byte(ELEMENT_TYPE_BYTE)

Take a look at the run-time type [4] above and notice the Element type
SZARRAY for the jagged array "jagged", SZARRAY is s type that indicates a
vector, an array with 0 bound and *no* upper bound. This is the way by which
the CLR makes a distiction between a "jagged array" and other array types,
the CLR treats them differently from the other types.
If you look at the snip in [3], you'll see the Rank being > 2, which is the
way by which the CLR distincts multi-dimentional arrays from other array
types. You can't have an array with Rank > 1 and Element type SZARRAY.

[2 ]show a regular array, that is Rank = 1 and Element type = CLASS.

[1] and [2] both define an array of element type CLASS, that means that they
are of the same Class (Execution Class) as such their instances point to the
same Method table, but the Class of [4] , is different from [1] (an array of
arrays of ...), so is it's Method table. The same is tru for [3] which is
treated differently as the others, this is reflected by it's Execution Class
which differs from the others.
See what I mean now?

Then what is the syntax for a managed jagged array in C++/CLI? Oh, it's
something like:

cli::array<cli::array<int>^>^

Not sure what you mean by this...
Anyway, make it:
array<array<Int32>^>^ local = gcnew array<array< Int32 >^>(2);
or:
array said:
to show that *only* one dimension (the first) can be specified, here we
declare "jagged arrays", using well defined language declaration syntax,
every
language has his own syntax, but finaly it boils down to the same thing.
based on a CLS compliant type from the CTS, and this is not true in C++.
in C#
int[3][] ja;
ja is a jagged array.

which is not possible in C++
int ja[3][];

The omitted dimension syntax is accepted in C and C++, but means something
entirely different. And I think it is the first dimension omitted, not
the last.

That's exactly the point, the you can ommit the first dimentions, never the
last, that means that you can only define a rectangular array using that
array syntax in C++. A jagged array *may* not specify the last dimension
will not compile.....
and
int ja[3][5];

is a two dimentional rectangular array, an array of arrays, but it's not
a jagged array!

No, it's not an array of arrays at all.

Right, my bad, no array of arrays, a two dimentional rectangular array, but
no jagged array.

It is a single array, and can be
treated interchangeable as a 3x5 array, a 5x3 array, or a 15 element
one-dimensional array.

int ja1[5], ja2[5], ja3[5];
int* ja[] = { ja1, ja2, ja3 };

is an array of arrays.
Right, still no jagged array.
Or, if you want to nitpick that this is an array of pointers,

int (&ja[])[5] = { ja1, ja2, ja3 };

Which is an array of arrays, but cannot be jagged.

Right, no jagged array.
P/invoke can't handle arrays of ref class types, and an array is a ref
class, so no, p/invoke can't do an array of arrays (or array of lists, or
list of arrays, or array of strings, or ...). Jagged arrays aren't a
special case in any sense.
Did I ever said otherwise?
It was me who said you can't pass a "jagged arrays" to C++, the PInvoke
marshaler has no knowlege on how to represent this type as an "unmanaged"
type (without creating a "new" kind of type of course).
That's why I asked the OP "why trying to pass a jagged array to C++". It
was me (and Nicholas) who said that the OP could pass a reference to a
single dimensional array or he should apply some custom marshaling, right?

Willy.
 
B

Ben Voigt [C++ MVP]

Are you telling me that "jagged arrays" are not a .NET language concept
based on a well defined type in the type system and the CLR (CLI)?

That is exactly what I am telling you. There is no concept of a jagged
array in the .NET runtime. What is a .NET language concept? .NET is an IL
runtime, not a language. It doesn't specify anything about the language.

C# may have special syntax for jagged arrays (I don't rightly remember, I
would have to look closely to see whether the dimensions are reversed in the
declaration), but translates them into a fundamental type: .NET array. The
element type of this array is itself an array type. There is no special
behavior from the .NET runtime.
The element type and shape of an array—including whether it is *jagged* or
*rectangular*, and the number of dimensions it has—are part of its type.
That why I keep saying that the declaration int[][] declares a distinct
well know array type!

Not distinct from object[] or string[]. It is basically a generic type
where the type argument is int[] (except that arrays were generic before the
runtime had support for arbitrary generic types).
Consider following snippets:

[1] An array of objects having an arrays of objects having an arrays of...
object[] oa = new object[2];
object[] oaa = new object[4];
oa[0] = oaa; // oa is an array of objects of array of objects
// Obviously the following is not possible, oa is not a jagged array
// oa[0][0] = new byte[4] {0, 2, 4, 6}; // NOT possible

Only because you have weak typing. This would work:

((object[])oa[0])[0] = new byte[4] { 0, 2, 4, 6 };
// Following is OK.
oaa[0] = new byte[4] {0, 2, 4, 6};

Here 'oa' Defines an System.Object[] with Rank = 1, holding 2 elements of
element type CLASS (ELEMENT_TYPE_CLASS to be precise),
element oa[0] holds a System.Object[] with Rank = 1, holding 4 elements of
element type is CLASS (ELEMENT_TYPE_CLASS),
element oaa[0] Defines an System.Byte[] with Rank = 1, holding 4 elements
of element type Byte(ELEMENT_TYPE_BYTE)

[2]
string[] sa = new string[2];
sa[0] = "somestring";
Here 'sa' defines an System.String[] with Rank = 1, holding 4 elements of
element type CLASS (ELEMENT_TYPE_CLASS)

[3]

byte[,] nonJagged = new byte[4,5];
nonJagged[0,0] = 100;
nonJagged[1,1] = 200;
Here 'sa' defines an System.Byte[] with Rank = 2, holding 20 elements of
element type Byte(ELEMENT_TYPE_BYTE)
Notice Rank=2, This is a multi-dimentional rectangular array.

[4]

byte[][][] jagged = new byte[4][][];
jagged[0] = new byte[1][] {
new byte[4] {1, 2, 3, 4}};
jagged[1] ....

Here 'jagged' defines an System.Byte[][][] with Rank = 1, holding 4
elements of element type SZARRAY(ELEMENT_TYPE_SZARRAY),
jagged[0] defines an System.Byte[][] with Rank = 1, holding 1 elements of
element type SZARRAY(ELEMENT_TYPE_SZARRAY)
and the element jagged[0] holds a reference to a
System.Byte[] with Rank = 1, holding 4 elements of element type
Byte(ELEMENT_TYPE_BYTE)

You just proved my point. jagged is an ordinary .NET array, each member of
which is byte[][].
Take a look at the run-time type [4] above and notice the Element type
SZARRAY for the jagged array "jagged", SZARRAY is s type that indicates a
vector, an array with 0 bound and *no* upper bound. This is the way by
which the CLR makes a distiction between a "jagged array" and other array
types, the CLR treats them differently from the other types.
If you look at the snip in [3], you'll see the Rank being > 2, which is
the way by which the CLR distincts multi-dimentional arrays from other
array types. You can't have an array with Rank > 1 and Element type
SZARRAY.

[2 ]show a regular array, that is Rank = 1 and Element type = CLASS.

[1] and [2] both define an array of element type CLASS, that means that
they are of the same Class (Execution Class) as such their instances point
to the same Method table, but the Class of [4] , is different from [1] (an
array of arrays of ...), so is it's Method table. The same is tru for [3]
which is treated differently as the others, this is reflected by it's
Execution Class which differs from the others.
See what I mean now?

Then what is the syntax for a managed jagged array in C++/CLI? Oh, it's
something like:

cli::array<cli::array<int>^>^

Not sure what you mean by this...
Anyway, make it:

(missing "using namespace System; using namespace cli;")
array<array<Int32>^>^ local = gcnew array<array< Int32 >^>(2);
or:

to show that *only* one dimension (the first) can be specified, here we
declare "jagged arrays", using well defined language declaration syntax,

This is not language syntax for jagged arrays. This is language syntax for
a use of a generic ref class named cli::array, where the type parameter is
cli::array said:
every
language has his own syntax, but finaly it boils down to the same thing.
based on a CLS compliant type from the CTS, and this is not true in C++.
in C#
int[3][] ja;
ja is a jagged array.

which is not possible in C++
int ja[3][];

The omitted dimension syntax is accepted in C and C++, but means
something
entirely different. And I think it is the first dimension omitted, not
the last.

That's exactly the point, the you can ommit the first dimentions, never
the
last, that means that you can only define a rectangular array using that
array syntax in C++. A jagged array *may* not specify the last dimension
will not compile.....
and
int ja[3][5];

is a two dimentional rectangular array, an array of arrays, but it's not
a jagged array!

No, it's not an array of arrays at all.

Right, my bad, no array of arrays, a two dimentional rectangular array,
but
no jagged array.

It's 15 elements laid out sequentially in memory.
It is a single array, and can be
treated interchangeable as a 3x5 array, a 5x3 array, or a 15 element
one-dimensional array.

int ja1[5], ja2[5], ja3[5];
int* ja[] = { ja1, ja2, ja3 };

is an array of arrays.
Right, still no jagged array.

Of course it is a jagged array. I can change the length of ja[0] without
changing the length of ja[1] or ja[2].

int ja4[6];

ja[0] = ja4;

Or, if you want to nitpick that this is an array of pointers,

int (&ja[])[5] = { ja1, ja2, ja3 };

Which is an array of arrays, but cannot be jagged.

Right, no jagged array.
P/invoke can't handle arrays of ref class types, and an array is a ref
class, so no, p/invoke can't do an array of arrays (or array of lists, or
list of arrays, or array of strings, or ...). Jagged arrays aren't a
special case in any sense.
Did I ever said otherwise?
It was me who said you can't pass a "jagged arrays" to C++, the PInvoke
marshaler has no knowlege on how to represent this type as an "unmanaged"
type (without creating a "new" kind of type of course).

Yes. You keep insisting that a jagged array is a special type. It is not.
If a jagged array was anything more than a composed array, then the
following would not work:

class Gen<T>
{
public static void UseIt(T[] t) { ... } // this is not a jagged array,
right?
}

int[][] a; // but this is a jagged array you say

Get<int[]>.UseIt(a); // passing a jagged array to a function that expects a
plain array?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top