VBAの定数の使い方と注意事項

このQ&Aのポイント
  • VBAの定数を使って計算値を定数に入れることはできません。定数には固定的な数値や文字列を入れるべきです。
  • 定数式には動的な要素を含めることはできません。計算値を定数に入れる場合は、変数を使用する必要があります。
  • VBAの定数はプログラムの実行中に変更することができないため、定数には固定的な値を入れることが重要です。
回答を見る
  • ベストアンサー

VBAの定数の使い方で、計算値を定数に入れることは可能ですか。

VBAの定数の使い方で、計算値を定数に入れることは可能ですか。 例えば、モジュール先頭に、 Option Explicit Const TEISU_COUNT As Integer = Application.WorksheetFunction.CountA(Range("A1:IV1")) と書き、その下に、 Sub TestTeisu()   MsgBox TEISU_COUNT   '↑定数式が必要です、のようなエラーが出ます。なぜでしょう?   'エラー時、「.CountA」にスポットがあたります。   'つまり、ここがダメということでしょうか?やはり、この点が動的だからでしょうか? End Sub と書いて、実行。 結果は、上述の通り、エラーとなります。 やはり、定数値には、固定的な数値(上記例では、Integer)や文字列を入れるべきなのでしょうか。 定数に入れることのできる値の注意事項について、 どなたかアドバイスして頂けますでしょうか。 宜しくお願い致します。

質問者が選んだベストアンサー

  • ベストアンサー
  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.3

#2の回答者です。 本当は、変数と定数の区別のつかない段階で、混乱するので、余計な話は聞かないで進めていったほうがよいのですが、一応、お答えしておきます。 定数は、変動したり値やプロパティを取得するものには使えません。だから、本来、比較のしようがありません。 グローバル変数のメリットとしては、一定の環境で、再取得することなく使えることです。主に、Auto_Open で取得して、最後まで使うことが多いです。グローバルにしておけば、他のプロシージャにでも、使えます。再取得する必要がないので、当然、処理スピードは上がります。 メモリについては、このレベルでは気にするほどのものはありません。String 型ですと、文字数に比例しますが、数値型は、仮にLong 型でも、4 Byte しかありません。Integer型は、2 Byte ですが、事実上、32ビットパソコンでは、4 Byte =32ビット分を使用します。メモリについては心配はほぼないと思います。処理速度の違いですが、定数と変数の違い自体は比べようもありませんが、再取得は別として、変数が100個も使うならともかく、その差は検知できないはずです。 グローバル変数のデメリットは、実は、マクロ稼働中にエラーが発生して、グローバル変数の内容がなくなってしまう、という問題があります。そうすると、以下のようなチェックコードが必要になるということがあります。 If g_Count =0 Then  Call RowCount End If '// Public g_Count As Integer Public Function RowCount()  g_Count = Application.WorksheetFunction.CountA(Range("A1:IV1")) End Function 普通は、こんなことは気にしなくてよいのですが、複雑な内容のマクロですと、必要になることがあります。また、なるべく、変数の名称は、プロシージャ内の変数とは区別がつくようにしてやることがコツです。こういうマクロは、1~2年レベルの経験では使わないと思います。 >ある固定的な値を入れる容器として、 >定数を使った場合でも、 >また、グローバル変数を使った場合でも動く 具体的な状況が思い浮かびません。どちらでも動くから、定数を使うというものでもないように思います。 前回も書いたように、消費税や数式の係数に対して用いるというのが、基本です。

nbsp0606
質問者

お礼

詳細な補足をありがとうございます。 定数とグローバル変数は、同じ土俵で比べられるものではないようですね。 用途が似ているようで似ていない、全くフィールドの異なる概念であるように思いました。 よって、両者のどちらを使うかで迷う、ということはない、ということなのでしょうね。 >具体的な状況が思い浮かびません。 苦し紛れに、具体的な状況を挙げさせて頂くと、 たとえば、 >グローバル変数のメリットとしては、一定の環境で、再取得することなく使えること とありましたが、 定数では、またげないスコープに対し、オールラウンドに、ある特定の値を使い回したい場合、 各スコープで、毎回、定数宣言をするよりかは、 どこか1箇所でグローバル変数宣言をして、その特定の値を使うようにしたほうが、 「その特定の値 に種類が50ほどある場合」なんかには、 コードが短くなり、メリットがあるのかなぁ、なんて思いましたが、いかがでしょう? その場合、 Public Sub Global_Var_Dim()   Public global_var01 as Single = 0.05   Public global_var02 as Single = 1.05   Public global_var03 as Single = 3.14     :     :   Public global_var48 as Single = 1.41421356   Public global_var49 as Single = 2.71828   Public global_var50 as Single = 1.7320568 End Sub こんなプロシージャを、どこか1箇所で実行するようにします。 一方、上記を定数で処理するとなると、 50個の特定の値を、各スコープで毎回、宣言することになりますよね。 これを私は冗長と考えたわけですが、何か見落としなどはありますでしょうか。 ※ まだVBA初心者であるため、文法的に変なことを言っているかもしれません。 考え方の大枠として、こんなことはできないだろうか~?といった話として、 解釈頂けると助かります。 もしまたよろしければ教えて下さい。

その他の回答 (3)

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.4

>定数では、またげないスコープに対し、オールラウンドに、ある特定の値を使い回したい場合、 >上記を定数で処理するとなると、50個の特定の値を、各スコープで毎回、宣言することになりますよね。 定数も変数も、基本的にはスコープは同じです。またげないということはありませんが、そこまでのレベルが必要になるというのは、入門の方からすれば、遥か彼方のテクニックだと思います。 Public global_Var(49) As Single '注:VBAでは、Single 型は慣例的にDouble型にすることが多い '私は、こういう場合は配列に確保します。 Private Sub Global_Var_Dim()   global_var(0) = 0.05   global_var(1) = 1.05   global_var(2) = 3.14   ・   ・   ・   ・   ・ End Sub または、Long型の場合は、列挙型にすることが多いです。 しかし、実際問題として、あまり、公にしていないのですが、プロの作ったものは、この場合、アドイン(.xla)にして、シートにデータを置き、そこから取り出す書かたをする人が多いようです。秘匿性がないので、あまり格好良くないのですが、決め打ちでやってみると、取り出すことが可能です。Excel VBAというものは、そういうものだとするしかありません。それ以外の方法(暗号化)もあるようですが、私自身、それ以上のことはしたことがありません。そこまで必要とされないからです。

nbsp0606
質問者

お礼

さらなる補足をありがとうございます。 >定数も変数も、基本的にはスコープは同じです。 あらら、では、私の挙げた例は適切ではありませんでしたね。苦笑 しかし、おかげさまで、 定数とグローバル変数の使い分けが少し分かったように思います。 ありがとうございます。 >シートにデータを置き、そこから取り出す書かたをする人が多いようです。 そういうテクニックもあるわけですね。 >'注:VBAでは、Single 型は慣例的にDouble型にすることが多い >'私は、こういう場合は配列に確保します。 こちらも、勉強になりました。 メモリのことを気にして、できる限り、Doubleは使わずにSingleで確実に大丈夫な所はSingleで、 なんて私は考えていましたが、業界の慣例ではDoubleにすることが多いのですか~、始めて知りました。 それでは、定数をドッサリ使って、作業を再開したいと思います。 終始、丁寧に回答下さり、ありがとうございました。

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.2

元のコードからすれば、以下のようにするのが自然だと思います。 '// Option Explicit Public g_Count As Integer '←Global 変数の場合は、標準モジュールに置きます。 'モジュールレベルなら、Private m_Count As Integer Sub TestMacro1() '←Global変数を使っている場合は、同じモジュールでなくても可能   g_Count = Application.WorksheetFunction.CountA(Range("A1:IV1"))  MsgBox g_Count End Sub 定数というのは、固定値ですから、変動しないことが条件です。 例えば、消費税として、Const RATE As Double = 0.05 など、定数(Constant)を使います。ワークシートの変動する条件の値を取る場合は、変数(Variable)です。

nbsp0606
質問者

お礼

.CountAなどを用いて計算した値を使い回す際に使用する「データの入れ物」は、 定数ではなくグローバル変数が良さそうですね。 当初、私は、例えば、消費税のような定数で良いようなものまで、 グローバル変数に入れて、固定的なグローバル変数というような扱いで、 まるで定数のように使っていたのですが、 「定数」そのものの存在を、ごく最近知りましたので、 定数にできるものは全て定数にしてしまおうと考え、 今回のような疑問にぶち当たりました。 定数で問題ないものを、仮にグローバル変数に入れて使う場合に考えられるメリット、デメリットがあれば、 教えて頂けると嬉しいです。 (どなたでも結構ですので、心当たりのある方、お願い致します。) 定数の場合、コード中に値が変更されてしまわない、 というメリットがあるように思いますが、それを踏まえた上で、 ここで私が知りたいメリットとは、具体的には、「処理速度」の面のメリットです。 メモリの食い、なども気になります。 ある固定的な値を入れる容器として、 定数を使った場合でも、 また、グローバル変数を使った場合でも動く という場合には、 やはり、グローバル変数ではなく、定数の方を使うべきなのでしょうか。 変なことを質問しているとは思いますが、 もしまた機会がございましたら、教えて下さい。

  • nag0720
  • ベストアンサー率58% (1093/1860)
回答No.1

>やはり、定数値には、固定的な数値(上記例では、Integer)や文字列を入れるべきなのでしょうか。 その通りです。 使えるのは、リテラル値、その他の定数、Isを除く算術演算子や論理演算子を組み合わせた式です。 シート関数の利用はもちろんシート内容も参照することはできませんし、VBAの関数も使うことはできません。 たとえば、 Const a As Single = 5.5 * 3 Sub Test() MsgBox Int(a) End Sub は大丈夫ですが、 Const a As Single = Int(5.5 * 3) Sub Test() MsgBox a End Sub はだめです。

nbsp0606
質問者

お礼

大変わかりやすい回答をありがとうございます。 >使えるのは、リテラル値、その他の定数、Isを除く算術演算子や論理演算子を組み合わせた式 上記に気をつけて、定数宣言をしていこうと思います。 分かりやすい具体例もありがとうございました。

関連するQ&A

  • 定数の宣言ってdimは使えないのですか?

    VBAです。 標準モジュールに Option Explicit Public Const フォルダ名 As String = "新しいフォルダー" Sub aaaa() End Sub はできるのですが、 Option Explicit dim Const フォルダ名 As String = "新しいフォルダー" Sub aaaa() End Sub は、エラーになってしまいます。 Option Explicit Sub aaaa() dim Const フォルダ名 As String = "新しいフォルダー" End Sub もダメみたいです。 定数を使うときは、必ずPublicで宣言しなけらばいけないのでしょうか?

  • エクセルVBAについて

    こんにちわ! 今、エクセルでAシートの入力した項目をBのシートへデーターが入力できるようなシステムを以下のようにくみました。 そこでBシートにデーターが入力されるのですが20行まで入力すると入力できないようにしたいのですが、なかなか上手くいきません。 A1からF20まで書式のロックを外しそれ以外のセルは保護をかけたのですがその状態でVBAを使って20行以上入力できませんという感じのエラー表示をしたいのですが、どうすればいいでしょうか? VBAは初心者ですが宜しくお願いします。 Private Sub CommandButton1_Click() Dim row As Integer row = WorksheetFunction.CountA(Sheets("date").Columns(1)) + 1 Sheets("date").Cells(row, 1).Value = Range("B2").Value row = WorksheetFunction.CountA(Sheets("date").Columns(2)) + 1 Sheets("date").Cells(row, 2).Value = Range("B3").Value row = WorksheetFunction.CountA(Sheets("date").Columns(3)) + 1 Sheets("date").Cells(row, 3).Value = Range("B4").Value row = WorksheetFunction.CountA(Sheets("date").Columns(4)) + 1 Sheets("date").Cells(row, 4).Value = Range("B5").Value row = WorksheetFunction.CountA(Sheets("date").Columns(5)) + 1 Sheets("date").Cells(row, 5).Value = Range("B6").Value row = WorksheetFunction.CountA(Sheets("date").Columns(6)) + 1 Sheets("date").Cells(row, 6).Value = Range("B7").Value Sheets("統制入力").Select Range("B17").Select ActiveWindow.SmallScroll Down:=-9 Range("B3:B7").Select Selection.ClearContents Range("B1").Select End Sub

  • Excel2003のVBAで教えてください

    以下のようなコードのプログラムを書いています。 使用しているシートは、"data"と"入力"という2つのシートです。 "入力"シート上で入力したデータを"data"シート上に追加していく予定です。 しかし、どうしても、"入力"シート上にペーストされてしまい"data"シート上にペーストすることができません。 Range("A" & z + 1).PasteSpecial Paste:=xlPasteValues が問題だとおもうのですが、これを Range("data!A" & z + 1).PasteSpecial Paste:=xlPasteValues と変更すると、実行時エラー1004になってしまいます。 アドバイスお願いします Private Sub CommandButton1_Click() Dim n As Integer Dim z As Long n = WorksheetFunction.CountA(Range("b9:b23")) Range("b51:f" & 51 + n - 1).Copy Set data = Worksheets("data").Range("A1") z = data.Rows.Count Sheets("data").Select Range("A" & z + 1).PasteSpecial Paste:=xlPasteValues MsgBox "登録しました" End Sub

  • 数が多い定数をスマートに処理するには?お知恵をお貸しください。

    Visual Basic(VB)6.0 です。フォームのTextなど各種入力の状態をチェックして、 不正なら該当する(ユーザ向けの)エラーメッセージを フォームのLabelに表示する処理を書いています。 エラーメッセージは20~30程度になり、全て定数Const文で持たせました。 随時発生する入力チェックの処理の度に、エラーならLabelのCaptionの表示を 変える処理を書くのはスマートではないと思ったので、 Label表示変更専用のモジュールを作ろうと考えました。 引数に(ユーザ定義の)コードを渡して、対応する定数のエラーメッセージを 判定・表示させる処理を書こうと思ったのですが、ここでうまくいきません。 以下、簡単なコードです。 ------------------------------------------------------ '* 定数です * Public Const ERR1 = "エラー1です" Public Const ERR2 = "エラー2です" Public Const ERR1 = "エラー3です" Public Const ERR2 = "エラー4です" '-----中略----- Public Const ERR50 = "エラー30です" ------------------------------------------------------- '** メイン処理です。** Sub main() Dim i As Integer 'フォームの入力をチェックします i = Chk_Value(dummy) If i > 0 Then '0より大きかったらエラーコードとして引数を渡します Call Disp_Msg(i) Exit Sub End If End Sub ------------------------------------------------------- '入力チェック処理です Private Function Chk_Value(ByVal dummy As Integer) As Integer '空白だったらエラーなので1を返します If Text1.Text = "" Then Chk_Value = 1 End If End Function ------------------------------------------------------- 'メッセージ表示処理です Private Sub Disp_Msg(ByVal ecd As Integer) '分からない! '引数で1を受け取り、定数のERR1を表示したい '引数で2を受け取ったら、定数のERR2を表示したい End Sub ------------------------------------------------------- 列挙型やType型変数もよい使い方が思いつかず、 ループで回して配列に格納しようにも、変数と変数を組み合わせて 変数を作る(wErr = "ERR" & i と書いても定数ERR1を表せない) のも無理なようだし、ほとほと困り果てています。 拙い説明で恐縮ですが、私の考えを実装することは可能でしょうか。 または別の方法はあるでしょうか。 よろしくお願いします。

  • rangeメソッドは失敗しました

    またまたエラーが起きてしまいました、、 D列にある数値の平均値を出すマクロを組みたいのですが そのD列は今後増えていくので変数を使い指定したいのです Option Explicit Public Sub all() Const SH_NAME As String = "VBA" Dim i Dim endrow As Long Dim ws As Worksheet Dim Result As Integer Set ws = ThisWorkbook.Worksheets(SH_NAME) With ws endrow = .Cells(Rows.Count, 4).End(xlUp).Row For i = 2 To endrow Result = Application.WorksheetFunction.Average(.Range("D2:D&i")) .Range("F39").Value = Result .Range("F39").NumberFormatLocal = "0.00" Next i End With End Sub このコードだと Result = Application.WorksheetFunction.Average(.Range("D2:D&i")) のところでrangeメソッドは失敗しました と言われてしまいます どうかよろしくお願いします<m(__)m>

  • 「定数式が必要です。」って何のこと?

    ExcelVBAで作成したマクロでデータ抽出を行なっていたのですが、 数日前に動作していたマクロが、突然に、 「定数式が必要です」というエラーが出てきて動かなくなりました。 VBAの仕様が変わったのでしょうか? ★エラーの発生したモジュール Option Explicit Dim MailCc As String Sub Mailer() (中略) MailTo = Cells(RW_TO, 2).Text ' 宛先 → MailCc = Cells(RW_CC, 2).Text ' CC (以下略) ★同一プロジェクトの別モジュール Global Const RW_CC = 18

  • VBAの簡略化について

    VBAで数値をカウントするマクロを作りました。  Dim Co1 As Integer Co1 = WorksheetFunction.CountIf(Range(Cells(○, ○), Cells(○, ○)), "<1") Dim Co2 As Integer Co2 = WorksheetFunction.CountIf(Range(Cells(○, ○), Cells(○, ○)), "<2") Dim Co3 As Integer Co3 = WorksheetFunction.CountIf(Range(Cells(○, ○), Cells(○, ○)), "<3") Dim Co4 As Integer Co4 = WorksheetFunction.CountIf(Range(Cells(○, ○), Cells(○, ○)), "<4") Dim Co5 As Integer Co5 = WorksheetFunction.CountIf(Range(Cells(○, ○), Cells(○, ○)), "<5") Dim Co6 As Integer Co6 = WorksheetFunction.CountIf(Range(Cells(○, ○), Cells(○, ○)), "<6") Dim Co7 As Integer Co7 = WorksheetFunction.CountIf(Range(Cells(○, ○), Cells(○, ○)), "<7") Dim Co8 As Integer Co8 = WorksheetFunction.CountIf(Range(Cells(○, ○), Cells(○, ○)), "<8") Dim Co9 As Integer Co9 = WorksheetFunction.CountIf(Range(Cells(○, ○), Cells(○, ○)), "<9") Dim Co10 As Integer Co10 = WorksheetFunction.CountIf(Range(Cells(○, ○), Cells(○, ○)), "<10") Dim Co11 As Integer Co11 = WorksheetFunction.CountIf(Range(Cells(○, ○), Cells(○, ○)), ">=10") Cells(2, 1) = Co1 Cells(3, 1) = Co2 - Co1 Cells(4, 1) = Co3 - Co2 Cells(5, 1) = Co4 - Co3 Cells(6, 1) = Co5 - Co4 Cells(7, 1) = Co6 - Co5 Cells(8, 1) = Co7 - Co6 Cells(9, 1) = Co8 - Co7 Cells(10, 1) = Co9 - Co8 Cells(11, 1) = Co10 - Co9 Cells(12, 1) = Co11 Cells(2, 1) = "0~0.999" Cells(3, 1) = "1~1.999" Cells(4, 1) = "2~2.999" Cells(5, 1) = "3~3.999" Cells(6, 1) = "4~4.999" Cells(7, 1) = "5~5.999" Cells(8, 1) = "6~6.999" Cells(9, 1) = "7~7.999" Cells(10, 1) = "8~8.999" Cells(11, 1) = "9~9.999" Cells(12, 1) = "10~" これを短くする方法を教えてください。

  • 定数にFullNameは使えないのですか?

    アクセスで、 Sub aaa() Const sPath As String = CurrentProject.FullName MsgBox sPath End Sub をすると、「定数式が必要です。」問われるのですが、上記のように定数に自身のfaiある名を入れたいのですが、無理なのでしょうか?

  • EXCEL VBAがうまく動きません。

    指定された rangeの中から2番目に小さい値を検索し、そのセルの行数を求めようとしていますが、えらーが出ます。いくつか試してみましたがだめでした。 初歩的な質問で恐縮ですが、教えてください。 構文は以下のように書きました。 Private Sub test() Dim s As Double Dim r As Range Dim secondsmall As range Dim smallrow as integer r = Worksheets("sheet1").Range("a1:a4") s = WorksheetFunction.Small(r, 2) secondsmall = WorksheetFunction.Find(what:=s) smallrow = secondsmall.row MsgBox smallrow end sub 宜しくお願いします。

  • Excel VBAでの定数宣言について

    初心者が書籍とにらめっこしながらマクロを書いています。 お助けください。 複数あるラジオボタンをクリックしたら、そのラジオボタンの種類に応じて、特定の行を表示したり、非表示にしたりしたいと考えています。行の追加や削除で行番号が変わってしまった場合に備えて、この行番号を定数として宣言したいと思ったのですが、うまくいきません。 シートモジュールには、以下のように記述しています。 ============================================================== Private Sub OptionButton1_Click() 'ラジオボタン1を選択 Rows(scope1).EntireRow.Hidden = False 'scope範囲行を表示 Rows(scope2).EntireRow.Hidden = True 'scope範囲行を非表示 End Sub Private Sub OptionButton2_Click() 'ラジオボタン1を選択 Rows(scope1).EntireRow.Hidden = True 'scope範囲行を非表示 Rows(scope2).EntireRow.Hidden = False  'scope範囲行を表示 End Sub ============================================================== 以下の記述で定数を宣言したいのですが、 public const scope1 = "38:48" '38行目~48行目 public const scope2 = "49:52" '49行目~52行目 シートモジュールの最初に書くと、 「コンパイルエラー  定数、固定長文字列、配列、ユーザー定義型およびDeclareステートメントは、オブジェクトモジュールのパブリックメンバとしては使用できません」 とエラーメッセージが表示されてしまいます。 エラーの意味がよく分からないのですが、定数宣言は、どこに記述すればよいのでしょうか? お教えください。よろしくお願いします。

専門家に質問してみよう