tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板 [ツリー表示へ]   [Home]
一括表示(VB6.0)
タイトル数値の1と文字列の"1"が同じになる理由
記事No16598
投稿日: 2020/12/06(Sun) 19:08
投稿者ヘンリー
私は、VB4.0、5.0、6.0を少し経験したことがございます。

しばらくプログラミングから離れていて、
最近ExcelのVBAを少しやっています。

自分の勉強のために、
とあるVBAの掲示板の投稿に対して、
回答をして差し上げようと思い、
解説用に簡単なコードを作成ていました。
そこで、どうしても納得のいかないことが発生しました。

現在は、VB4.0、5.0、6.0の環境がないので
試すことができず、こちらのVBの掲示板に
質問をさせていただいた次第です。
もし、VB6.0なら「数値の1と文字の列が等しくない」と
判定されるのでしょうか。


私の中では、VBもVBAも以下のコードなら
変わらないと思っているのですが、
どうしても、数値の1と文字列の"1"が
等しく扱われる理由がわかりません。


お分かりの方がいらっしゃいましたら、
ご享受して頂けないでしょうか。
※VB6.0や、VB2005以降だと数値と文字が違うと
判断するかどうかだけでも、構いませんので、
教えていただけるとありがたいです。

何卒宜しくお願い致します。

Sub Sample()
    Dim a As String
    Dim b As Integer
    
    a = "1"
    b = 1
    
  '↓本来、If CStr(b) = a Thenの様に
  ' 型を合わせてから比較、と書くべきとは思うのですが…
    If b = a Then  
    'If文の判定結果がTrueになる理由がどうしてもわかりません
        Debug.Print True 
    Else
        Debug.Print False
    End If
    
    'ここまでのコードで、数値1と文字列"1"が等しく扱われているので、
    '以下のコードを追加したところ、変数aは文字列演算(a+"1"="11")、
    '変数bは数値演算(b+1=2)されています。
    a = a + "1"
    b = b + 1
    
    Debug.Print a
    Debug.Print b

End Sub

[ツリー表示へ]
タイトルRe: 数値の1と文字列の"1"が同じになる理由
記事No16601
投稿日: 2020/12/07(Mon) 12:05
投稿者魔界の仮面弁士
> 最近ExcelのVBAを少しやっています。
VB6 も VBA も言語エンジンは一緒なので、判断基準は変わりません。
VBA の最新は 7.1 なので、言語仕様的には VB6 の方が古いですが。


>   '↓本来、If CStr(b) = a Thenの様に
>   ' 型を合わせてから比較、と書くべきとは思うのですが…
>   If b = a Then  
比較式の一方が数値型で、他方が文字列型ですね。
この組み合わせの場合、両端が Double 型へと暗黙の型変換されてから比較される仕様です。

こうした変換ルールは一応ヘルプにも書いてあるのですが、ちょっと分かりにくいですよね。
https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/comparison-operators


要するに今回の場合、
  If b = a Then
という処理が
  If CDbl(b) = CDbl(a) Then
に相当する判定式として処理されることになります。

そのため以下の組み合わせは、いずれも「If a = b Then」が True として判定されます。
 a = "&HA"
 b = 10

 a = "(100)"
 b = -100


一方、文字列側を数値に変換できないようなケース…たとえば
  a = ""
  b = 1
のような場合には、CDbl(a) 相当の型変換が行えないため、
VB6 や VBA では『実行時エラー '13': 型が一致しません。』
.NET 版の VB では『System.InvalidCastException: 'String "" から型 'Double' への変換は無効です。』
というエラーになります。



>     Dim a As String
>     Dim b As Integer
>     a = "1"
>     b = 1
二つの項に対する演算において、それぞれの項のデータ型が異なる場合、
それが比較演算であれ代入演算であれ算術演算であれ、まずは暗黙の型変換が働きます。

今回の場合、比較式の一方が数値型だったので、数値同士の演算として処理されたわけです。


これが代入処理であったならば、たとえば
 Dim a As String
 Dim b As Integer
 a = -1     '文字列型変数に整数値を代入 … CStr(-1) 相当で "-1"
 b = "2.5"  '整数型変数に文字列値を代入 … CInt(CDbl("2.5")) 相当で 2
 b = "3.5"  '整数型変数に文字列値を代入 … CInt(CDbl("2.5")) 相当で 2
と書いたとしても、特にエラーにはなりません。


比較演算であれ、四則演算であれ、同様の型変換が行われます。
  11  +  11  は 22     になります。
  11  + "11" は 22.0   になります。
 "11" +  11  は 22.0   になります。
 "11" + "11" は "1111" になります。
  11  &  11  は "1111" になります。
  11  & "11" は "1111" になります。
 "11" &  11  は "1111" になります。
 "11" & "11" は "1111" になります。


蛇足ですが、VBA において
  x / y
という除算演算は、基本的には Double 型として演算されます。

Debug.Print TypeName("24" / "2")         ' "Double"
Debug.Print TypeName(CCur(1) / CInt(1))  ' "Double"
Debug.Print TypeName(CLng(1) / CLng(1))  ' "Double"
Debug.Print TypeName(CCur(1) / CCur(1))  ' "Double"
Debug.Print TypeName(CDec(1) / CDec(1))  ' "Decimal"
Debug.Print TypeName(CSng(1) / CSng(1))  ' "Single"

x / y という割り算の結果は、ほとんどが Double 型となりますが、例外的な組み合わせとして
x と y の一方が Decimal の場合は、演算結果は Decimal 型になります。
x と y の一方が Single で、他方が Byte, Integer, Single いずれかなら、Single 型に演算されます。
x と y の一方または両方が Null なら、演算結果も Null です。
(なお、Empty 値を渡した場合には、数値ゼロとして扱われます)
https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/forwardslash-operator


> ご享受して頂けないでしょうか。
享受:与えられたものを自分のものとして受け入れ、味わい楽しむこと
 →「インターネットの恩恵を享受する」
教授:専門的な学問や技芸を教え授けること
 →「書道を教授する」
教示:知識や方法などを教え示すこと
 →「御教示を賜りたい」
http://www.tt.rim.or.jp/~rudyard/torii009.html



> ※VB6.0や、VB2005以降だと数値と文字が違うと
VB6 やそれ以前でも同じですし、
VB.NET (2002)、VB.NET 2003、VB2005 はもちろん、
VB2008、VB2010、VB2012、VB2013、VB2015、VB2017、VB2019 でも
この点は変わっていません。

ただし .NET では、『Option Strict On』指定でコンパイルした場合には、
データ型の違いまでチェックされるようになっています。

[ツリー表示へ]
タイトルRe^2: 数値の1と文字列の"1"が同じになる理由
記事No16602
投稿日: 2020/12/07(Mon) 15:47
投稿者ヘンリー
魔界の仮面弁士様
丁寧なご回答のおかげで、理解できました。
又、誤字についてもご指摘して頂き、
誠にありがとうございます。

魔界の仮面弁士様におかれましては、
かつて自分がVB5.0、6.0をやっていた時に、
度々助けて頂いておりました。

あらためて感謝いたします。
本当にありがとうございました。

[ツリー表示へ]