To dziwne dziwactwo VBA. Jestem zaskoczony, że nigdy nie wpadłem na to.
Dim x As Long
x = 24 * 60 * 60 ' Overflow
x = 32767 + 1 ' Overflow.
x = 32768 + 1 ' Works fine!
Wygląda więc na to, że operatorzy *
i +
zwracać liczbę całkowitą w pierwszych dwóch przykładach. Rzeczywiście, w pliku pomocy dla operatora *
(podobny do operatora +
):
result = number1 * number2
[...]
The data type of result is usually the same as that of the most precise expression.
Twoje literałów 24, 60 i 60 są typu Integer domyślnie, więc operator *
(lub +
) zwraca liczbę całkowitą, która przepełnia, ponieważ wynik jest większy niż 32 767.
Jednak dosłownie 32 768 w trzecim przykładzie jest domyślnie typu Long (ponieważ jest zbyt duży, aby być liczbą całkowitą), a więc +
zwraca wartość Long; brak przepełnienia.
Plik pomocy również mówi w ten sposób:
If [...] the data type of result is an Integer variant that overflows its legal range [...] Then result is [...] converted to a Long variant.
Nacisk kopalni. Teraz ta mała zasada brzmi zdroworozsądkowo i każdy mógłby rozsądnie założyć, że ma ona zastosowanie w twoim przypadku. Ale twoje liczby są typu Integer, a nie Variant/Integer, więc VBA nie stosuje tej reguły! Nie ma dla mnie absolutnie żadnego sensu, ale tak właśnie jest i tak mówi dokumentacja.
Rozwiązanie: jeden z argumentów twojego operatora *
powinien być bardziej precyzyjny niż Integer (na przykład Long), a problem zniknie.
x = CLng(24) * 60 * 60 ' Result is Long, works fine.
W rzeczywistości, a to pewnie dlatego nigdy nie wpadł na to dziwactwo, robię zwyczaj deklarowania wszystkich moich zmiennych Integer tak długo, zamiast tego, o ile istnieje szczególne obawy, że zamiast posiadające typu Long Liczby całkowite spowodują problemy z wykorzystaniem pamięci lub czasem wykonania (co prawie nigdy się nie zdarza). To prawda, że nie pomoże to w przypadkach, gdy operujesz na literałach mniejszych niż 32 768, ponieważ domyślnie są to typy typu Integer.
Pytasz w a comment czym jest wariant/liczba całkowita. Wariant jest w zasadzie typem kontenera dla dowolnego innego typu danych. W szczególnym przypadku, w którym można zrobić to zawierać Integer:
Dim a As Variant ' a is now Empty
a = CInt(32767) ' a is now Variant/Integer
x = a + 1 ' works fine
Ale jak wspomniano powyżej, zwykły stary Integer wyzwala błąd przepełnienia:
Dim b As Integer
b = 32767
x = b + 1 ' overflow
W związku z tym. - jeśli wstawię msgbox 26 * 60^2 w bezpośrednim oknie, nie ma problemu. Czy jest to kwestia porządku pierwszeństwa? To wydaje się mało prawdopodobne ... –
Dzieje się tak dlatego, że operator '^' zwraca Double, który omija problem opisany w mojej odpowiedzi poniżej. –