I noticed that if I do
a = min (b,c)
I often got a warning that both b and c must be double and not integer. That's because while double can be converted to integer on the fly, the other way around doesn't work.
And the reason why it should work is because b and c is passed by reference.
However, why?
min (b,c) simply takes the smaller value of b or c and return it into a
Why should the argument is passed by ref? The function doesn't change the value of it's parameter?
Since you set vb.net as the tag:
Min() function (Math.Min) is overloaded and can take arguments of the following types: byte, decimal, single, double, signed and unsigned integers of different sizes (2, 4 or 8 bytes)
Both arguments should be of the same type, otherwise implicit conversion will take place. Your statement "That's because while double can be converted to integer on the fly, the other way around doesn't work." is not accurate; see code below.
Your statement "And the reason why it should work is because b and c is passed by reference." is not true either; see code below.
This following code should compile and run fine:
Module VBModule
Sub Main()
Console.WriteLine(Math.Min(5.1, 4))
End Sub
End Module
Related
According to this documentation by Microsoft, the following code can be used to make sure;
a, b, and c are all Single; x and y are both Double
Dim a, b, c As Single, x, y As Double, i As Integer
> a, b, and c are all Single; x and y are both Double
The logic behind this is as follows
You can specify different data types for different variables by using a separate As clause for each variable you declare. Each variable takes the data type specified in the first As clause encountered after its variable name part.
However, when I checked with the debugger or MsgBox VarType(a) output, this is not the case.
As you can see, it appears that As is only working for the variables right before itself, ie., c, y and i. All others are Variant/Empty and VarType returns 0.
Is this just the documentation being wrong, or am I missing something obvious?
Microsoft Visual Basic for Application 7.1.1056
Excel 2016 (Windows 10)
The documentation you've linked to isn't wrong, but it's written for VB.NET and not VBA.
In VBA, as you've observed, any variable declarations that aren't immediately followed by As <type> will be Variant.
Therefore you'd need to write:
Dim a As Single, b As Single, c As Single, x As Double, y As Double, i As Integer
In VBA, when you declare
Dim a, b, c As Single
What it does is equivalent to this:
Dim a As Variant, b As Variant, c As Single
I believe the best practice is to always declare variable in a separate row. It prevents this bug and also allows for faster scanning of the code. So the code would look like this:
Dim a As Single
Dim b As Single
Dim c As Single
When I run the following macro:
Sub try()
Dim num As Integer
num = 123
MsgBox Len(num)
MsgBox VBA.Len(num)
End Sub
The first Msgbox displays 2 and the second Msgbox displays 3.
If I remove the first line which says Dim num As Integer, both MsgBoxes display 3.
Can anyone explain why?
Len and LenB are not just ordinary functions, they are keywords, and as such are found on the list of VBA keywords (although LenB is only mentioned after you click through to Len).
Mid would be another example of such keyword disguised as function, whereas e.g. Left isn't on the list at all, because that is just an ordinary function.
It has to be a keyword because one of its jobs is to perform the compile-time task of determining the storage size of a variable. E.g. with private user-defined types, an ordinary function could not do that at all:
Private Type foo
a As Long
b As String
End Type
Sub TestLens()
Dim f As foo
MsgBox Len(f) ' OK
MsgBox VBA.Len(f) ' Compile time error
End Sub
The fact that the object browser brings you to VBA.Len when you press Shift+F2 on that Len(f) is both correct and misleading.
The Len(f) here does not actually call the VBA.Len function that determines the string size, it simply cannot do that because it would require coercing a private struct into a Variant. Instead it calculates the size of foo at compile time and substitutes the result as a literal constant into the executable.
In your example the Len(num) calculates the compile-time size of variable num (which is 2) and substitutes the constant 2 into the resulting object code, whereas VBA.Len(num) packs the value of num into a Variant and passes that variant to VBA.Len where it's further converted to string "123" and the length of that is returned.
It has to do with the way that VB stores integers and how the Len() function handles arguments that are not strings.
When a datatype that is not a string is passed to the Len() function, it returns the nominal number of bytes used to store the data (VB uses 2 bytes to store an integer). See the documentation for the Len function.
The Len() function will automatically cast the variant variable (which is created by assigning a value to a variable without declaring it first) as a string. The return isn't changing because the storage allocation changes (although it does; variants require 16 bytes of storage space, minimum). Since the implicitly declared variable is actually a variant type, VB will automatically change its type based on the situation. In this case, Len() expects a string so VB makes the variable a string.
You could use Msgbox Len(Cstr(num)) to cast the integer variable as a string before passing it to the Len function if your intent is to return the number of characters in your integer value.
Hi so im making a program in VB.Net which will hopefully output the MD5 hash of a string without using System.Security.Cryptography (not the smartest but i fancied a challenge) using the implementation from here: https://www.rfc-editor.org/rfc/rfc1321
Anyway im getting an Arithmetic overflow when i run my code. Up until this point it has been running rather smoothly with the inputted string being converted to binary, padded correctly etc.
However when i get to stage 4 where i have to process the message block it goes a little strange. Specifically on this function where it returns an Arithmetic overflow on the line labelled:
Function R1(ByRef a As ULong, ByRef b As Integer, ByRef c As Integer, ByRef d As Integer, ByRef splitmessagepart As String, ByRef S As Integer, ByRef i As Integer, ByRef T() As Long)
'the line below returns the arithmetic overflow
a = b + ((a + (f(b, c, d)) + splitmessagepart + T(i)) << S)
Return a
End Function
This is function F:
Function f(ByRef X As String, ByRef Y As String, ByRef Z As String)
Dim endresult As String
endresult = (X And Y) Or (Not X And Z)
Return endresult
End Function
And then this is the line which calls the function R1:
splitmessagepart = splitmessage(0)
a = R1(a, b, c, d, splitmessagepart, 7, 1, T)
Through some debugging i have found that my splitmessagepart variable isnt correctly translated from Binary to decimal in another function but even if i change it so that it is the correct decimal version i still get the overflow. Im assuming this happens on the other 3 functions also which do something similar to this however the program encounters an error on the first line.
I was wondering if i could have a little help figuring out why this is happening? If theres any code needed that i havent put in please ask i really want to get this to work!
Thanks
You should split the calculation into its parts and check precisely with the watch which operator throws the exception.
More importantly, it looks like you have set the option strict off. This not a good practice unless you absolutely have to. You define the parameters of the function f as string, but you pass Integers to it, so they will implicitly converted to strings. Inside f you use and and or which will again implicitly convert your parameters because these operators are not defined on strings. Also you have not defined the type of the output of the function.
More over you have defined splitmessagepart as string and you try to use + between strings and integers. Are you aware what the result will be.
I advise you to turn the option strict on and check on all these implicit conversions, they are probably not what you expect.
FYI, the doc states that a word is a 32-bit object, so an integer. I doubt there should be a string anywhere in the algorithm.
I am trying to create a 600*600 Matrix as user-defined type and later use this type for other Matrices. The Problem is it's throwing an error stating that the variable size of "content" cannot be more than 64kb.
My code is as follows:
Type Matrixtype
Contents(1to600,1 to600) As double
End Type
From here https://msdn.microsoft.com/en-us/library/office/gg278742.aspx
The size of a user-defined type exceeds 64K.
Reduce the size of the user-defined type. Generally the size of a user-defined type equals the sum of the sizes specified for its elements. On some platforms there may be padding between the elements to keep them aligned on word boundaries. If you nest one user-defined type in another, the size of the nested type must be included in the size of the new type.
Doubles are 8 bytes. 360,000 doubles is 2.9 million bytes (~2,800 kb). That's why you can't have a data structure of Doubles that's 600 square. You also can't have 150 square unless you change the data type to something smaller than a Double.
I'm not sure what you're trying to accomplish with this, so the best advice I can give you is to create a class and maintain the array in there. Create a class and name the module CTest. In it, put this code
Private mdContents(1 To 600, 1 To 600) As Double
Public Property Let Contents(ByVal lOne As Long, ByVal lTwo As Long, ByVal dValue As Double)
mdContents(lOne, lTwo) = dValue
End Property
Public Property Get Contents(ByVal lOne As Long, ByVal lTwo As Long) As Double
Contents = mdContents(lOne, lTwo)
End Property
Now, in a standard module, you can create however many copies of this class that you need.
Public Sub Test()
Dim clsOne As CTest
Dim clsTwo As CTest
Set clsOne = New CTest
clsOne.Contents(1, 1) = 2 ^ 2
Set clsTwo = New CTest
clsTwo.Contents(10, 10) = 2 ^ 3
Debug.Print clsOne.Contents(1, 1), clsTwo.Contents(10, 10)
End Sub
When I run the following macro:
Sub try()
Dim num As Integer
num = 123
MsgBox Len(num)
MsgBox VBA.Len(num)
End Sub
The first Msgbox displays 2 and the second Msgbox displays 3.
If I remove the first line which says Dim num As Integer, both MsgBoxes display 3.
Can anyone explain why?
Len and LenB are not just ordinary functions, they are keywords, and as such are found on the list of VBA keywords (although LenB is only mentioned after you click through to Len).
Mid would be another example of such keyword disguised as function, whereas e.g. Left isn't on the list at all, because that is just an ordinary function.
It has to be a keyword because one of its jobs is to perform the compile-time task of determining the storage size of a variable. E.g. with private user-defined types, an ordinary function could not do that at all:
Private Type foo
a As Long
b As String
End Type
Sub TestLens()
Dim f As foo
MsgBox Len(f) ' OK
MsgBox VBA.Len(f) ' Compile time error
End Sub
The fact that the object browser brings you to VBA.Len when you press Shift+F2 on that Len(f) is both correct and misleading.
The Len(f) here does not actually call the VBA.Len function that determines the string size, it simply cannot do that because it would require coercing a private struct into a Variant. Instead it calculates the size of foo at compile time and substitutes the result as a literal constant into the executable.
In your example the Len(num) calculates the compile-time size of variable num (which is 2) and substitutes the constant 2 into the resulting object code, whereas VBA.Len(num) packs the value of num into a Variant and passes that variant to VBA.Len where it's further converted to string "123" and the length of that is returned.
It has to do with the way that VB stores integers and how the Len() function handles arguments that are not strings.
When a datatype that is not a string is passed to the Len() function, it returns the nominal number of bytes used to store the data (VB uses 2 bytes to store an integer). See the documentation for the Len function.
The Len() function will automatically cast the variant variable (which is created by assigning a value to a variable without declaring it first) as a string. The return isn't changing because the storage allocation changes (although it does; variants require 16 bytes of storage space, minimum). Since the implicitly declared variable is actually a variant type, VB will automatically change its type based on the situation. In this case, Len() expects a string so VB makes the variable a string.
You could use Msgbox Len(Cstr(num)) to cast the integer variable as a string before passing it to the Len function if your intent is to return the number of characters in your integer value.