Interop: size_t, UIntPtr, and UIntPtr::Operator-

  • Thread starter Thread starter Jeffrey Walton
  • Start date Start date
J

Jeffrey Walton

Hi All,

I'm working on a VB program that calls into a C++/Crypto++ dll. The
Crypto++ and the Dll makes heavy use of size_t, so factoring out the
size_t is not an option.

In VB, I need an array of a known size. VB has a perverted behavior of
Dim'ing size+1 rather than size. So I'm stuck when allocating the
array

C++/Crypto++ pseudo code declaration:
size_t GetRequiredSize();

Visual Basic:
UintPtr size = GetRequiredSize()
Dim arr(0 To size-1) as Byte

Attempting to allocate the array causes Error BC30452: Operator '-' is
not defined for types 'System.UIntPtr' and 'Integer'.

I can't use an Integer since Integers are 4 bytes on both x86 and x64
platforms. The following compiles, but the Length is wrong (off by
one);
Dim arr(maxsize) As Byte

Any ideas?

Thanks,
Jeffrey Walton
 
Jeffrey said:
[...]
Visual Basic:
UintPtr size = GetRequiredSize()
Dim arr(0 To size-1) as Byte

Attempting to allocate the array causes Error BC30452: Operator '-' is
not defined for types 'System.UIntPtr' and 'Integer'.

What about converting to a type that does define the '-' operator? For
example:

Dim arr(0 to size.ToUInt64() - 1) as Byte

Pete
 
Hi Pete,

Jeffrey said:
[...]
Visual Basic:
UintPtr size = GetRequiredSize()
Dim arr(0 To size-1) as Byte
Attempting to allocate the array causes Error BC30452: Operator '-' is
not defined for types 'System.UIntPtr' and 'Integer'.

What about converting to a type that does define the '-' operator?  For
example:

   Dim arr(0 to size.ToUInt64() - 1) as Byte
I don't believe I can due to lack of a preprocessor. Or is there a
preprocessor in VB?

#ifdef x86
Dim arr(0 to size.ToUInt32() - 1) as Byte
#else ifdef x64
Dim arr(0 to size.ToUInt64() - 1) as Byte
#endif

Jeff
 
Jeffrey said:
I don't believe I can due to lack of a preprocessor. Or is there a
preprocessor in VB?

#ifdef x86
Dim arr(0 to size.ToUInt32() - 1) as Byte
#else ifdef x64
Dim arr(0 to size.ToUInt64() - 1) as Byte
#endif

Not sure what you mean. Why do you need a preprocessor? Can't you just
always use UInt64? Why does it have to be UInt32 on a 32-bit system?

Pete
 
Jeffrey said:
Hi All,

I'm working on a VB program that calls into a C++/Crypto++ dll. The
Crypto++ and the Dll makes heavy use of size_t, so factoring out the
size_t is not an option.

In VB, I need an array of a known size. VB has a perverted behavior of
Dim'ing size+1 rather than size.

No, it's not perverted because you do not specify the size. You specify
the upper bound. With a zero based index, the size is upper bound + 1.
This is because of previous versions that were also able to specify
the optional lower bound:

dim arr([LowerBound To] UpperBound)

If this had been changed, many VB programmers would have been made very unhappy,
you know.


So I'm stuck when allocating the
array

C++/Crypto++ pseudo code declaration:
size_t GetRequiredSize();

Visual Basic:
UintPtr size = GetRequiredSize()
Dim arr(0 To size-1) as Byte

The Dim/ReDim statements always expect a value in the range of the Integer
data type, which is always 32 bits. You'd have to use the Array.CreateInstance
method that also accepts a Long value (paramarray).
Attempting to allocate the array causes Error BC30452: Operator '-' is
not defined for types 'System.UIntPtr' and 'Integer'.

I can't use an Integer since Integers are 4 bytes on both x86 and x64
platforms. The following compiles, but the Length is wrong (off by
one);
Dim arr(maxsize) As Byte

Any ideas?

As we do not know the size of an IntPtr at design time - if the AnyCPU target
is specified - we have to decide at runtime.

In this special case, as Array.CreateInstance expects a _signed_ int32/int64, I choose
the Long data type also for the 32-Bit version. Otherwise, sizes > 2GB (Int32.maxvalue)
would even fail on a 32-Bit system. It's another story if it makes sense; it's just for
technical correctness.

Now that we use the Long type, and consequently CreateInstance, also on a 32 bit system,
there's no need to calculate an upper bound because CreateInstance expects the _length_
of the array:

Dim size As UIntPtr
Dim arr As Byte()
Dim Length As Long

Length = If(UIntPtr.Size = 4, CLng(size.ToUInt32), CLng(size.ToUInt64))

arr = DirectCast(Array.CreateInstance(GetType(Byte), Length), Byte())

Well, the above will fail if size > Long.MaxValue..... but back to reality. If I have to calculate
with (U)IntPtrs, I use this approach:

Dim UpperBound As UIntPtr

UpperBound = If( _
UIntPtr.Size = 4, _
New UIntPtr(size.ToUInt32 - 1UI), _
New UIntPtr(size.ToUInt64 - 1UL) _
)

Note the UI vs UL suffix.


In addition, you can check the target platform with conditional compilation:

#If PLATFORM = "x64" Then 'or "AnyCPU", or "x86"

So, the code above is for AnyCPU, but you may decide to use smaller code
with a different target.
 
Hi Armin,

Jeffrey said:
I'm working on a VB program that calls into a C++/Crypto++ dll. The
Crypto++ and the Dll makes heavy use of size_t, so factoring out the
size_t is not an option.
In VB, I need an array of a known size. VB has a perverted behavior of
Dim'ing size+1 rather than size.

No, it's not perverted because you do not specify the size. You specify
the upper bound. With a zero based index, the size is upper bound + 1.
This is because of previous versions that were also able to specify
the optional lower bound:

   dim arr([LowerBound To] UpperBound)

If this had been changed, many VB programmers would have been made very unhappy,
you know.
Agreed. BTW, are you aware of any other languages which specify an
upper bound (and/or lower bound) versus a size?
The Dim/ReDim statements always expect a value in the range of the Integer
data type, which is always 32 bits. You'd have to use the Array.CreateInstance
method that also accepts a Long value (paramarray).




As we do not know the size of an IntPtr at design time - if the AnyCPU target
is specified - we have to decide at runtime.

In this special case, as Array.CreateInstance expects a _signed_ int32/int64, I choose
the Long data type also for the 32-Bit version. Otherwise, sizes > 2GB (Int32.maxvalue)
would even fail on a 32-Bit system. It's another story if it makes sense;it's just for
technical correctness.

Now that we use the Long type, and consequently CreateInstance, also on a32 bit system,
there's no need to calculate an upper bound because CreateInstance expects the _length_
of the array:

      Dim size As UIntPtr
      Dim arr As Byte()
      Dim Length As Long

      Length = If(UIntPtr.Size = 4, CLng(size.ToUInt32), CLng(size.ToUInt64))

      arr = DirectCast(Array.CreateInstance(GetType(Byte), Length), Byte())

Well, the above will fail if size > Long.MaxValue..... but back to reality. If I have to calculate
with (U)IntPtrs, I use this approach:

      Dim UpperBound As UIntPtr

      UpperBound = If( _
          UIntPtr.Size = 4, _
          New UIntPtr(size.ToUInt32 - 1UI), _
          New UIntPtr(size.ToUInt64 - 1UL) _
      )

Note the UI vs UL suffix.
OK. I think I'll punt since there does not appear to be a clean
solution. The CLR folks will simply be limited to 2^32 (which should
be more than enough).
In addition, you can check the target platform with conditional compilation:

#If PLATFORM = "x64" Then     'or "AnyCPU", or "x86"
Interesting. I was not able to get this to work:

#If PLATFORM = "x86" Then
Dim maxsize As UInt32 = 0
#ElseIf PLATFORM = "x64" Then
Dim maxsize As UInt64 = 0
#Else
' Signal error - unexpected platform
#End If

' Do something with maxsize
' error BC30451: Name 'maxsize' is not declared.

I also tried "X86", "X64", x86 (without quotes), and x64.

Thanks for the help,
Jeff
 
Jeffrey said:
Agreed. BTW, are you aware of any other languages which specify an
upper bound (and/or lower bound) versus a size?

Pascal comes to mind. Probably Delphi too, since that was based in part
on Pascal, but I don't know for sure. I'm sure Google can help you out
with that. :)

I'm confident there are a number of other examples of languages that
allow that sort of thing.
[...]
Interesting. I was not able to get this to work:

#If PLATFORM = "x86" Then
Dim maxsize As UInt32 = 0
#ElseIf PLATFORM = "x64" Then
Dim maxsize As UInt64 = 0
#Else
' Signal error - unexpected platform
#End If

' Do something with maxsize
' error BC30451: Name 'maxsize' is not declared.

I also tried "X86", "X64", x86 (without quotes), and x64.

I still don't understand your desire to change the type used depending
on platform. I see from the previous comment that in VB.NET you can't
specify a 64-bit value as the dimension even on the 64-bit platform, but
all that means is that you need to use a different way to allocate the
array instance (as Armin pointed out). In that different way, you
should always be able to use a 64-bit length, regardless of platform.

Pete
 
Jeffrey said:
Agreed. BTW, are you aware of any other languages which specify an
upper bound (and/or lower bound) versus a size?

No, I am not aware of another language where you are able to specify
upper and lower bounds.
[...]
Dim UpperBound As UIntPtr

UpperBound = If( _
UIntPtr.Size = 4, _
New UIntPtr(size.ToUInt32 - 1UI), _
New UIntPtr(size.ToUInt64 - 1UL) _
)

Note the UI vs UL suffix.
OK. I think I'll punt since there does not appear to be a clean
solution.

Why do you think it is not a clean solution? As computations with IntPtrs
do not exist (at least in VB.Net), we have to use Integers or Longs depending
on the platform.
The CLR folks will simply be limited to 2^32 (which should
be more than enough).

Limitted with arrays or in which respect?

Interesting. I was not able to get this to work:

#If PLATFORM = "x86" Then
Dim maxsize As UInt32 = 0
#ElseIf PLATFORM = "x64" Then
Dim maxsize As UInt64 = 0
#Else
' Signal error - unexpected platform
#End If

' Do something with maxsize
' error BC30451: Name 'maxsize' is not declared.

Which is the selected target platform? If it's "AnyCPU" - which is
your #Else branch - it is not declared indeed. Then the error is correct.
 
Hi Pete,

Pascal comes to mind.  Probably Delphi too, since that was based in part
on Pascal, but I don't know for sure.  I'm sure Google can help you out
with that.  :)
I remembered Pasacal used, for example, arr[0 .. x]. But I could not
remember if there was arr[size].
I'm confident there are a number of other examples of languages that
allow that sort of thing.
[...]
Interesting. I was not able to get this to work:
#If PLATFORM = "x86" Then
    Dim maxsize As UInt32 = 0
#ElseIf PLATFORM = "x64" Then
    Dim maxsize As UInt64 = 0
#Else
    ' Signal error - unexpected platform
#End If
    ' Do something with maxsize
    ' error BC30451: Name 'maxsize' is not declared.
I also tried "X86", "X64", x86 (without quotes), and x64.

I still don't understand your desire to change the type used depending
on platform.
I think that's my C/C++ background, and the desire to build
executables for a particular platform.

Jeff
 
Back
Top