2016-09-12 41 views
6

Theo MSDN, cho Variant kiểu dữ liệu:VBA: Hành vi bất ngờ của Variant Data Type

“dữ liệu Numeric thể được bất kỳ số nguyên hoặc giá trị số thực khác nhau, từ -1.797693134862315E308 để -4.94066E-324 cho âm . giá trị và từ 4.94066E-324 để 1.797693134862315E308 cho các giá trị tích cực”

tuy nhiên, đoạn mã sau đưa ra một lỗi mặc dù tất cả các giá trị cuối cùng sau khi tính toán rơi cũng trong phạm vi chấp nhận được:

Sub Test() 

Dim v1, v2, v3, v4 

v1 = 569847501 + 54678     ' OKAY 
v2 = 7784687414# + 98565821345#   ' OKAY 
v3 = 7784687414# + 1132747441   ' OKAY 
v4 = 1132747441 + 1788441323   ' FAILS 

End Sub 

MSDN cũng chỉ ra:

”Tuy nhiên, nếu một hoạt động số học được thực hiện trên một Variant chứa một Byte, một Integer, một dài, hoặc một đơn, và kết quả vượt quá phạm vi bình thường đối với bản gốc kiểu dữ liệu, kết quả được thăng hạng trong Biến thể thành kiểu dữ liệu lớn hơn tiếp theo. Một Byte được thăng lên một Số nguyên, một Số nguyên được thăng cấp thành một Giá trị dài, và một số nguyên và một đơn được quảng cáo thành một giá trị gấp đôi. ”

Tài liệu nêu rõ rằng loại này phải được quảng bá khi hoạt động số học vượt quá phạm vi bình thường cho kiểu dữ liệu gốc. Tại sao không phải là v4 được thăng cấp lên Double?

+2

Lưu ý rằng đây không phải là duy nhất đối với 'Biến thể'. 'Dim d As Double: d = 1132747441 + 1788441323' thực hiện chính xác điều tương tự. – Comintern

Trả lời

6

Bạn đang làm việc với các chữ số, không phải là Biến thể. Chúng được biên dịch bởi trình biên dịch là kiểu cần thiết nhỏ nhất để chứa giá trị bằng chữ, mặc dù các giá trị Byte sẽ mặc định là loại Integer.

Debug.Print TypeName(1132747441) 'Long 
Debug.Print TypeName(1788441323) 'Long 

Như @ComIntern chỉ ra, bạn đang giao kết quả của 2 chờ đợi trong một biểu thức, khái niệm tràn trước khi nó được gán cho các biến thể v4

Như @dazedandconfused chỉ ra, bạn có thể ép buộc các giá trị theo nghĩa đen cho loại phù hợp hơn và biểu thức sẽ đánh giá và biến thể có thể được gán.

Để nhận được hành vi mà Microsoft ghi lại cho loại Biến thể, bạn cần phải ép buộc giá trị bằng chữ cho biến thể, trước khi sử dụng biểu thức. Cả hai Biến thể sẽ là chứaLong s, nhưng bạn sẽ tự động nhập lại tài liệu khẳng định.

Sub Test() 

    Dim v1, v2, v3, v4 

    Debug.Print TypeName(1132747441) 'Long 
    Debug.Print TypeName(1788441323) 'Long 

    Dim v5, v6 

    v5 = 1132747441 
    v6 = 1788441323 

    Debug.Print TypeName(v5) 'Long 
    Debug.Print TypeName(v6) 'Long 

    v4 = v5 + v6 'OKAY 
    Debug.Print TypeName(v4) 'Double 

    v4 = 0 
    Debug.Print TypeName(v4) 'Integer 

    v4 = CVar(1132747441) + CVar(1788441323) ' OKAY 
    Debug.Print TypeName(v4) 'Double 


    v1 = 569847501 + 54678     ' OKAY 
    v2 = 7784687414# + 98565821345#   ' OKAY 
    v3 = 7784687414# + 1132747441   ' OKAY 
    v4 = 1132747441 + 1788441323   ' FAILS 

End Sub 
6

Từ https://support.microsoft.com/en-us/kb/199809 - Xem in đậm tuyên bố

Tuyên bố này tạo ra một lỗi tràn bộ nhớ, kể từ 24 * 24 * 60 = 34560, vượt quá kích thước tối đa của một số nguyên 2 byte (32767). Visual Basic không đánh giá toàn bộ biểu thức để kiểm tra kích thước của kết quả, nhưng thay vào đó tiếp tục sử dụng khoảng cách tạm thời 2 byte để tính toán. Lỗi tràn tương tự xảy ra nếu bạn khai báo các giá trị trước đó làm hằng số và nhân các hằng số.

Để làm việc xung quanh hành vi này, điều quan trọng là luôn luôn nhập số rõ ràng khi sử dụng chúng trong phép tính số hoặc khi xác định hằng số. Nếu biểu thức trước được thay đổi để các sau:

Vì vậy, thay đổi nó để ...

v4 = 1132747441# + 1788441323# 

... hiện các trick, nhưng nó chắc chắn không mùi.

+1

'v4 = 2921188764' là một mẹo tốt hơn nhiều. – Comintern

Các vấn đề liên quan