Vba ошибка variable not defined

I am a long time avid Excel user but am just starting to learn VBA. I am using the following code but am getting an error when I try to run Sub test:

Compile Error:Variable not defined

Can you help me figure out what is wrong?

Option Explicit

Function toFarenheit(degrees)
    toFarenheit = (9 / 5) * degrees + 32
End Function

Function toCentigrade(degrees)
    toCentigrade = (5 / 9) * degrees - 32
End Function

Sub test()
    answer = toCentigrade(55)
    MsgBox answer    
End Sub

RubberDuck's user avatar

RubberDuck

12k5 gold badges50 silver badges95 bronze badges

asked Dec 29, 2014 at 19:43

Alyss's user avatar

You have Option Explicit turn on which means you must declare your variables before using them.

In Sub test, you are missing a declaration for answer. Adding this should fix it:

Sub test()
    Dim answer As Variant
    answer = toCentigrade(55)
    MsgBox answer    
End Sub

Edit

Since you are new to VBA, you might want to consider typing both your variables and function returns. You don’t have to do this (and everything will be treated as a Variant), but it is good practice.

If you type everything properly, your example would become:

Option Explicit

' Accept a double value and return a double type value.
Function toFarenheit(degrees As Double) As Double
    toFarenheit = (9 / 5) * degrees + 32
End Function

Function toCentigrade(degrees As Double) As Double
    toCentigrade = (5 / 9) * degrees - 32
End Function

Sub test()
    ' Variable type matches what the function will return.
    Dim answer As Double
    answer = toCentigrade(55)
    MsgBox answer    
End Sub

answered Dec 29, 2014 at 19:52

Jason Faulkner's user avatar

Jason FaulknerJason Faulkner

6,4082 gold badges28 silver badges33 bronze badges

3

I tested this to convert to farenheit

The function is as follows

Function ToFarenheit(Degrees As Double)

ToFarenheit = (9 / 5) * Degrees + 32

End Function

The sub is as follows

Sub TestFunction()

MsgBox ToFarenheit(0)

End Sub

answered Dec 29, 2014 at 19:52

bilbo_strikes_back's user avatar

1

Хитрости »

1 Май 2011              52587 просмотров


Option Explicit — начинающие программировать в Visual Basic могут увидеть данную строку в чужом коде, либо случайно в своем. Хотя кто-то может быть уже знает, что это и зачем и использует данное объявление намеренно. Я же постараюсь максимально подробно описать смысл этой строки и её полезность для кода в первую очередь для тех, кто еще не знает для чего она.

Строка данная записывается в самом начале модуля, самой первой строкой. Перед этой строкой ничего более не может быть записано, кроме, разве что других подобных строк(есть еще другие :-))

Собственно что же делает эта строка? А делает она следующее: она принуждает Вас объявлять переменные(если не знаете смысл объявления переменных — читайте здесь). Если какая-либо переменная внутри выполняемой процедуры не объявлена — Вы увидите такое вот сообщение:

рис.1

так же редактор VBA выделит ту переменную, которая не объявлена. Первое время это может раздражать. Да и вообще: зачем это? Вы и без всех этих объявлений неплохо жили. А вот зачем

  • во-первых: объявление переменных считается хорошим тоном при программировании
  • во-вторых: правильное присвоение типов недурно экономит память
  • ну и в-третьих(я бы даже сказал в главных): это помогает избежать неявных ошибок кода при несовпадении типов данных

А теперь перейдем к сути и попробуем разобраться в чем же польза от использования Option Explicit. Ниже приведен простой код:

Sub Check_Variables()
    Dim a As String
    a = "Привет от www.excel-vba.ru"
    MsgBox а, vbInformation
End Sub

Выполните данный код без строки Option Explicit. Какое значение выдаст MsgBox? Ничего. Что за странность? Ведь явно видно, что переменной присвоено значение текста. Ничего больше не происходит. Но переменная все равно пуста. Мистика…А теперь запишите первой строкой в модуле Option Explicit:

Option Explicit
Sub Check_Variables()
    Dim a As String
    a = "Привет от www.excel-vba.ru"
    MsgBox а, vbInformation
End Sub

Запустите код. И что же видите? Видите сообщение, показанное на рис.1 и выделенную переменную «а», в последней строке. Что это означает? Это означает, что переменная «а» у нас не объявлена. А все потому, что первой строкой (Dim a As String) я объявил переменную на английском языке, а в последней строке я записал её на русском. А для кода это разные символы. Если разглядеть логику работы VBA — первую «а» он видит как переменную с присвоенным типом String. И ей мы задаем значение «Привет от www.excel-vba.ru». А вторую…Вторую он не находит в объявленных переменных, не находит в функциях и сам инициализирует её как новую переменную с типом данных Variant. И, что вполне логично, со значением Empty, т.е. ничего, т.к. этой переменной мы никаких значений не присваивали.

Еще один классический пример, когда Option Explicit спасет от лишних мозговых штурмов. Имеем простую функцию пользователя(UDF), которая берет указанную дату и возвращает её в заранее заданном формате в текстовом виде:

Function GetDateAsText(Optional ByVal Дата As Date)
    If Дата = 0 Then
        Дата = Date
    End If
    GetDataAsText = Format(Дата, "DD MMMM YYYY")
End Function

Хоть функция и короткая, но даже в ней не сразу порой бросается в глаза опечатка(представим, если функция в реальности строк на 200). В итоге чаще всего автор функции не понимает, почему при записи её на листе она возвращает не дату вида «21 мая 2016», а 0 и начинает пошагово выполнять функцию, искать ошибки в логике кода и т.д. Но если поставить в начало модуля Option Explicit, то при первом же выполнении этой функции VBA подсветит нам «GetDataAsText = «, указывая тем самым, что GetDataAsText в чем-то отличается от заданного имени функции — GetDateAsText. Банальная опечатка: GetDataAsText — GetDateAsText.


А теперь представьте себе, что Вы написали кучу длинного кода, строк на 100 или более. Конечно, Option Explicit Вы не используете. И вот Вы тестируете код, но он работает как-то не так…Где-то что-то неверно выполняется. И Вы начинаете пошагово ковыряться в листинге и искать ошибку…А ведь все может быть и проще: где-то в коде Вы могли банально опечататься и присвоить таким образом значение переменной, на которую Вы и не рассчитывали. А если использовать Option Explicit, то такая опечатка будет сразу обнаружена еще до выполнения кода и, что немаловажно — подсвечена. Так что Вам даже не придется её искать, а останется лишь исправить ошибку.

Так же эта строка поможет избежать неявных ошибок и в других ситуациях. В частности, при обращении к другим приложениями(Word, Outlook и т.д.). Например, в Excel применяются именованные константы для многих задач. Одна из распространенных — поиск последней ячейки в столбце: llast = Cells(Rows.Count, 1).End(xlUp).Row
здесь xlUp является именованной константой, значение которой равно числу: -4162. В других приложениях такой же подход. Это избавляет от необходимости помнить на память все значения констант и обращаться к ним при помощи intellisense. Но действуют эти константы исключительно внутри своего приложения(можете обратить внимание, у Excel константы начинаются с xl, а у Word — с wd). И т.к. объявлены эти константы в других приложениях — Excel про них не знает(как и другие приложения не знают про константы Excel). Для примера возьмем простой и рабочий код замены в Word:

    Dim wdDoc As Object
    Set wdDoc = objWordApp.ActiveDocument
    With wdDoc.Range.Find
        .Text = "привет"
        .Replacement.Text = "привет"
        .wrap = wdFindContinue
        .Execute Replace:=wdReplaceAll
    End With

Где wdFindContinue для Word-а равно 1, а wdReplaceAll = 2. Но это происходит только при выполнении изнутри самого Word-а(или при раннем связывании через ToolsReferences. Подробнее про это можно почитать в статье: Как из Excel обратиться к другому приложению).

Если же скопировать и выполнять данный код из Excel, то работать он будет не так как задумали. Дело в том, что Вы считаете, что Excel работает с обозначенными константами(wdFindContinue, wdReplaceAll) наравне с Word-ом. Но Excel на самом деле про них ничего не знает. И если директива Option Explicit будет отключена, то Excel просто назначает им значение по умолчанию — Empty. Которое преобразуется в 0. А это совсем иной поиск получается, т.к. должны быть значения 1 и 2. А если бы Option Explicit была включена, то Excel выделил бы их и указал, что они не объявлены. И тогда можно было бы сделать либо так:

    Dim wdDoc As Object
    Const wdFindContinue As Long = 1
    Const wdReplaceAll As Long = 2
    Set wdDoc = objWordApp.ActiveDocument
    With wdDoc.Range.Find
        .Text = "привет"
        .Replacement.Text = "привет"
        .wrap = wdFindContinue
        .Execute Replace:=wdReplaceAll
    End With

либо так(что удобнее, на мой взгляд):

    Dim wdDoc As Object
    Set wdDoc = objWordApp.ActiveDocument
    With wdDoc.Range.Find
        .Text = "привет"
        .Replacement.Text = "привет"
        .wrap = 1
        .Execute Replace:=2
    End With

Так что думаю, не стоит недооценивать значимость строки Option Explicit при написании кодов. В довершение хотелось бы Вас обрадовать, что вписывание данной строки в начало каждого модуля можно сделать автоматическим: поставить в опциях редактора галочку: ToolsOptions-вкладка EditorRequire Variable Declaration. Теперь во всех новых созданных модулях строка Option Explicit будет создаваться самим редактором VBA автоматически. К сожалению, в уже имеющихся модулях Вам придется проставить данную строку самим вручную. Но это того стоит, поверьте.

Так же см.:
Что такое переменная и как правильно её объявить?


Статья помогла? Поделись ссылкой с друзьями!

  Плейлист   Видеоуроки


Поиск по меткам



Access
apple watch
Multex
Power Query и Power BI
VBA управление кодами
Бесплатные надстройки
Дата и время
Записки
ИП
Надстройки
Печать
Политика Конфиденциальности
Почта
Программы
Работа с приложениями
Разработка приложений
Росстат
Тренинги и вебинары
Финансовые
Форматирование
Функции Excel
акции MulTEx
ссылки
статистика

 

nicex

Пользователь

Сообщений: 167
Регистрация: 26.07.2015

#1

12.07.2019 15:15:57

Добрый день!, выдает ошибку Compile error: variable not defined

Код
 For i = 1 To Cells(Rows.Count, "D").End(xlUp).Row

       If Cells(i, 7) = "TNK" Or Cells(i, 7) = "RST" Or Cells(i, 7) = "TY" Then Cells(i, 10) = "SS"
 Next



 Dim i As Long
 Dim iLastRow As Long
 iLastRow = Cells(Rows.Count, "B").End(xlUp).Row

  For i = iLastRow To 1 Step -1
    If Cells(i, 7) = 1 And Cells(i, 8) < 2500 Then Rows(i).ClearContents
  Next

Я поменял местаим части кода

Код
 Dim i As Long
 Dim iLastRow As Long
 iLastRow = Cells(Rows.Count, "D").End(xlUp).Row

   For i = iLastRow To 1 Step -1
  
        If Cells(i, 7) = "TNK" Or Cells(i, 7) = "RST" Or Cells(i, 7) = "TY" Then Cells(i, 10) = "SS"
   Next



 iLastRow = Cells(Rows.Count, "B").End(xlUp).Row

  For i = iLastRow To 1 Step -1
    If Cells(i, 7) = 1 And Cells(i, 8) < 2500 Then Rows(i).ClearContents
  Next

Подскажите корректно макрос будет работать ?

 

Nordheim

Пользователь

Сообщений: 3154
Регистрация: 18.04.2017

У вас таблица заполнена не полностью? почему в двух циклах последняя заполненная строка ищется по разным столбцам?

Изменено: Nordheim12.07.2019 15:25:00

«Все гениальное просто, а все простое гениально!!!»

 

nicex

Пользователь

Сообщений: 167
Регистрация: 26.07.2015

Nordheim, это только часть макроса

 

Sanja

Пользователь

Сообщений: 15282
Регистрация: 10.01.2013

#4

12.07.2019 15:42:43

Цитата
nicex написал: Подскажите корректно макрос будет работать ?

А самому попробовать?  

Согласие есть продукт при полном непротивлении сторон.

 

Nordheim

Пользователь

Сообщений: 3154
Регистрация: 18.04.2017

#5

12.07.2019 15:49:14

Цитата
nicex написал:
это только часть макроса

Я вижу, это не ответ на вопрос, если нужна последняя строка диапазона, то  я не вижу смысла в двух циклах,
да и Select Case , как по мне, в данном случае предпочтительней.

«Все гениальное просто, а все простое гениально!!!»

 

nicex

Пользователь

Сообщений: 167
Регистрация: 26.07.2015

Sanja, я попробовал, работает, но проблема проверить результат, опасаюсь что в макросе что то не корректно обрабатывается, поэтому хочу понять не приведет ли такая замена на обум к ошибкам

Nordheim, мои возможности только методом тыка адаптировать готовый код

 

Nordheim

Пользователь

Сообщений: 3154
Регистрация: 18.04.2017

#7

12.07.2019 16:02:16

Цитата
nicex написал:
мои возможности только методом тыка адаптировать готовый код

Вы не знаете как ответить на вопрос

Цитата
Nordheim написал:
почему в двух циклах последняя заполненная строка ищется по разным столбцам?

или не хотите, меня не интересовало полный это макрос или часть, я это и так вижу.

Цитата
nicex написал:
мои возможности только методом тыка адаптировать готовый код

про ваши методы я так же не спрашивал. Вопрос тут в таком случае такой, а вы уверены что код вообще работает правильно, коли вы не знаете почему определение последней заполненной строки производится по разным столбцам?

«Все гениальное просто, а все простое гениально!!!»

 

nicex

Пользователь

Сообщений: 167
Регистрация: 26.07.2015

Nordheim, я объединил два разных макроса. перед второй частью макроса :

////// iLastRow = Cells(Rows.Count, «B»).End(xlUp).Row

 For i = iLastRow To 1 Step -1
   If Cells(i, 7) = 1 And Cells(i, 8) < 2500 Then Rows(i).ClearContents
 Next /////

происходит перестановка колонок и еще какие то замены и тп и тд

 

Sanja

Пользователь

Сообщений: 15282
Регистрация: 10.01.2013

Ошибка исчезла? Значит решение задачи, вынесенной в название Темы получено. Все остальное ЭТОЙ темы не касается.
Вы сначала разберитесь, что Вы хотите от этого макроса, а уже потом задавайте вопросы, конкретные, в других темах

Согласие есть продукт при полном непротивлении сторон.

 

Jack Famous

Пользователь

Сообщений: 11431
Регистрация: 07.11.2014

OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome

#10

12.07.2019 16:41:01

Цитата
nicex: Compile error: variable not defined

объявите переменную. Для того, чтобы в будущем этого избежать, прочтите

инструкцию

Прикрепленные файлы

  • 1.png (8.23 КБ)

Изменено: Jack Famous12.07.2019 16:41:33

Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄

 

nicex

Пользователь

Сообщений: 167
Регистрация: 26.07.2015

Jack Famous, спасибо

Sanja, как изменить тему на: Я поменял местаим части кода будет ли корректно макрос работать ?

 

vikttur

Пользователь

Сообщений: 47199
Регистрация: 15.09.2012

Такая ошибка может возникнуть в тысячах разных кодов.
Как назовем тему, пмощники?

 
название темы:

что значит сообщение Compile error: variable not defined при попытке выполнить макрос?

ответ:

в сообщении все сказано: Ошибка компилятора: неопределенная переменная!
эта  значит что в начале модуля есть инструкция Option Explicit которая требует обьявления ЛЮБОЙ переменной прежде, чем она будет использована в коде

решение:

1. удалите строку Option Explicit
или
2.напишите Option Explicit Off
или
3. обьявите перменную (Din переменная as…) раньше, чем обращаетесь к ней где-либо в коде
удачи!

Программисты — это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!

 

RAN

Пользователь

Сообщений: 7207
Регистрация: 21.12.2012

Вить, коды-то разные, причина одна.
И название ничем не хуже

этого

, или

этого

 

vikttur

Пользователь

Сообщений: 47199
Регистрация: 15.09.2012

Андрей, одна в Курилке, по второй более-менее понятно по названию.
А по этой… Вчитываться во все темы нет возможности, вижу обсуждение кода… поэтому и спрашиваю — как переименовать. Если не надо — оставим.

 

Dima S

Пользователь

Сообщений: 2063
Регистрация: 01.01.1970

#16

13.07.2019 01:53:01

Цитата
Ігор Гончаренко написал:
(Din переменная as…)

Dim

  • Remove From My Forums
  • Question

  • Hi,

    very old code with many-many colons….

    ' COMPILE:  Variable not defined......>vbCrLf<.................FALSE /Compile Error !!!
    ' COMPILE:  Variable not defined......>gkxPAC_NAME_SHRT<.......TRUE
    Option Compare Database
    Option Explicit
    '--------------------------------
    'Private Const gkxPAC_NAME_SHRT = ""
    'Private Const gkxPACAppMainVersion = ""
    'Private Function APP_QUIT(Optional cMsg$ = "")
    'On Error GoTo xPAC_CHYBA
    'Dim lc__proc_meno$, lc__proc_ErrUSR$, ln__proc_err&
    'lc__proc_meno$ = "APP_QUIT"
    'If Len(cMsg) > 0 Then MsgBox cMsg & vbCrLf & String(50, "-") & vbCrLf & gkxPAC_NAME_SHRT & " " & gkxPACAppMainVersion, vbExclamation + vbSystemModal, gkxPAC_NAME_SHRT & ", " & lc__proc_meno
    'LBL_EXIT:
    'Application.Quit
    'xPAC_KONIEC:
    'Exit Function
    'xPAC_CHYBA:
    'MsgBox "Err: " & Err.Number & "," & Err.Description & vbCrLf & String(50, "-") & vbCrLf & gkxPAC_NAME_SHRT & " " & gkxPACAppMainVersion, vbCritical + vbSystemModal, gkxPAC_NAME_SHRT & ", " & lc__proc_meno & ", E" & "rr" & "or !"
    'Resume LBL_EXIT
    'End Function
    '--------------------------------
    ' COMPILE:  Variable not defined......>vbCrLf<.................FALSE /Compile Error !!!
    ' COMPILE:  Variable not defined......>gkxPAC_NAME_SHRT<.......TRUE
    Private Function APP_QUIT(Optional cMsg$ = ""): On Error GoTo xPAC_CHYBA: Dim lc__proc_meno$, lc__proc_ErrUSR$, ln__proc_err&: lc__proc_meno$ = "APP_QUIT": If Len(cMsg) > 0 Then MsgBox cMsg & vbCrLf & String(50, "-") & vbCrLf & gkxPAC_NAME_SHRT & " " & gkxPACAppMainVersion, vbExclamation + vbSystemModal, gkxPAC_NAME_SHRT & ", " & lc__proc_meno
    LBL_EXIT: Application.Quit
    xPAC_KONIEC: Exit Function
    xPAC_CHYBA: MsgBox "Err: " & Err.Number & "," & Err.Description & vbCrLf & String(50, "-") & vbCrLf & gkxPAC_NAME_SHRT & " " & gkxPACAppMainVersion, vbCritical + vbSystemModal, gkxPAC_NAME_SHRT & ", " & lc__proc_meno & ", E" & "rr" & "or !": Resume LBL_EXIT
    End Function


    dBase,FoxPro,MS Access 2003,(2010=Not rec.),Office 2010+ACC.2013 ,Symbian C++, AC.2013.SystemResource.GetCurrentFreeSize=?

Answers

  • Hi PACALA_BA,

    >> the main  point is NOT „Variable not defined“

    Did you mean that you could make your code work, and you are wondering why the Selected undefined variable is wrong if you did not define the gkxPAC_NAME_SHRT?

    I have made a test with your code, and I could reproduce your issue. If I test with the code below, the error message with the selected is correct.

    Option Compare Database
    Option Explicit
    '--------------------------------
    'Private Const gkxPAC_NAME_SHRT = ""
    'Private Const gkxPACAppMainVersion = ""
    'Private Function APP_QUIT(Optional cMsg$ = "")
    'On Error GoTo xPAC_CHYBA
    'Dim lc__proc_meno$, lc__proc_ErrUSR$, ln__proc_err&
    'lc__proc_meno$ = "APP_QUIT"
    'If Len(cMsg) > 0 Then MsgBox cMsg & vbCrLf & String(50, "-") & vbCrLf & gkxPAC_NAME_SHRT & " " & gkxPACAppMainVersion, vbExclamation + vbSystemModal, gkxPAC_NAME_SHRT & ", " & lc__proc_meno
    'LBL_EXIT:
    'Application.Quit
    'xPAC_KONIEC:
    'Exit Function
    'xPAC_CHYBA:
    'MsgBox "Err: " & Err.Number & "," & Err.Description & vbCrLf & String(50, "-") & vbCrLf & gkxPAC_NAME_SHRT & " " & gkxPACAppMainVersion, vbCritical + vbSystemModal, gkxPAC_NAME_SHRT & ", " & lc__proc_meno & ", E" & "rr" & "or !"
    'Resume LBL_EXIT
    'End Function
    '--------------------------------
    ' COMPILE:  Variable not defined......>vbCrLf<.................FALSE /Compile Error !!!
    ' COMPILE:  Variable not defined......>gkxPAC_NAME_SHRT<.......TRUE
    'Private Function APP_QUIT(Optional cMsg$ = ""): On Error GoTo xPAC_CHYBA: Dim lc__proc_meno$, lc__proc_ErrUSR$, ln__proc_err&: lc__proc_meno$ = "APP_QUIT": If Len(cMsg) > 0 Then MsgBox cMsg & vbCrLf & String(50, "-") & vbCrLf & gkxPAC_NAME_SHRT & " " & gkxPACAppMainVersion, vbExclamation + vbSystemModal, gkxPAC_NAME_SHRT & ", " & lc__proc_meno
    'LBL_EXIT: Application.Quit
    'xPAC_KONIEC: Exit Function
    'xPAC_CHYBA: MsgBox "Err: " & Err.Number & "," & Err.Description & vbCrLf & String(50, "-") & vbCrLf & gkxPAC_NAME_SHRT & " " & gkxPACAppMainVersion, vbCritical + vbSystemModal, gkxPAC_NAME_SHRT & ", " & lc__proc_meno & ", E" & "rr" & "or !": Resume LBL_EXIT
    'End Function
    Private Function test()
        MsgBox "Hello" & vbCrLf & undefinedVariable
    End Function

    To be honesty, I do not know why this happened, I used the Editor for developer, but I did not know the details achievement of it.

    I suggest you define all the variable you will use in the code, write the correct code.

    Best Regards,

    Edward


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.

    Click
    HERE to participate the survey.

    • Marked as answer by

      Tuesday, August 25, 2015 1:10 PM

Хитрости »

1 Май 2011              50922 просмотров


Option Explicit — начинающие программировать в Visual Basic могут увидеть данную строку в чужом коде, либо случайно в своем. Хотя кто-то может быть уже знает, что это и зачем и использует данное объявление намеренно. Я же постараюсь максимально подробно описать смысл этой строки и её полезность для кода в первую очередь для тех, кто еще не знает для чего она.

Строка данная записывается в самом начале модуля, самой первой строкой. Перед этой строкой ничего более не может быть записано, кроме, разве что других подобных строк(есть еще другие :-))

Собственно что же делает эта строка? А делает она следующее: она принуждает Вас объявлять переменные(если не знаете смысл объявления переменных — читайте здесь). Если какая-либо переменная внутри выполняемой процедуры не объявлена — Вы увидите такое вот сообщение:

рис.1

так же редактор VBA выделит ту переменную, которая не объявлена. Первое время это может раздражать. Да и вообще: зачем это? Вы и без всех этих объявлений неплохо жили. А вот зачем

  • во-первых: объявление переменных считается хорошим тоном при программировании
  • во-вторых: правильное присвоение типов недурно экономит память
  • ну и в-третьих(я бы даже сказал в главных): это помогает избежать неявных ошибок кода при несовпадении типов данных

А теперь перейдем к сути и попробуем разобраться в чем же польза от использования Option Explicit. Ниже приведен простой код:

Sub Check_Variables()
    Dim a As String
    a = "Привет от www.excel-vba.ru"
    MsgBox а, vbInformation
End Sub

Выполните данный код без строки Option Explicit. Какое значение выдаст MsgBox? Ничего. Что за странность? Ведь явно видно, что переменной присвоено значение текста. Ничего больше не происходит. Но переменная все равно пуста. Мистика…А теперь запишите первой строкой в модуле Option Explicit:

Option Explicit
Sub Check_Variables()
    Dim a As String
    a = "Привет от www.excel-vba.ru"
    MsgBox а, vbInformation
End Sub

Запустите код. И что же видите? Видите сообщение, показанное на рис.1 и выделенную переменную «а», в последней строке. Что это означает? Это означает, что переменная «а» у нас не объявлена. А все потому, что первой строкой (Dim a As String) я объявил переменную на английском языке, а в последней строке я записал её на русском. А для кода это разные символы. Если разглядеть логику работы VBA — первую «а» он видит как переменную с присвоенным типом String. И ей мы задаем значение «Привет от www.excel-vba.ru». А вторую…Вторую он не находит в объявленных переменных, не находит в функциях и сам инициализирует её как новую переменную с типом данных Variant. И, что вполне логично, со значением Empty, т.е. ничего, т.к. этой переменной мы никаких значений не присваивали.

Еще один классический пример, когда Option Explicit спасет от лишних мозговых штурмов. Имеем простую функцию пользователя(UDF), которая берет указанную дату и возвращает её в заранее заданном формате в текстовом виде:

Function GetDateAsText(Optional ByVal Дата As Date)
    If Дата = 0 Then
        Дата = Date
    End If
    GetDataAsText = Format(Дата, "DD MMMM YYYY")
End Function

Хоть функция и короткая, но даже в ней не сразу порой бросается в глаза опечатка(представим, если функция в реальности строк на 200). В итоге чаще всего автор функции не понимает, почему при записи её на листе она возвращает не дату вида «21 мая 2016», а 0 и начинает пошагово выполнять функцию, искать ошибки в логике кода и т.д. Но если поставить в начало модуля Option Explicit, то при первом же выполнении этой функции VBA подсветит нам «GetDataAsText = «, указывая тем самым, что GetDataAsText в чем-то отличается от заданного имени функции — GetDateAsText. Банальная опечатка: GetDataAsText — GetDateAsText.


А теперь представьте себе, что Вы написали кучу длинного кода, строк на 100 или более. Конечно, Option Explicit Вы не используете. И вот Вы тестируете код, но он работает как-то не так…Где-то что-то неверно выполняется. И Вы начинаете пошагово ковыряться в листинге и искать ошибку…А ведь все может быть и проще: где-то в коде Вы могли банально опечататься и присвоить таким образом значение переменной, на которую Вы и не рассчитывали. А если использовать Option Explicit, то такая опечатка будет сразу обнаружена еще до выполнения кода и, что немаловажно — подсвечена. Так что Вам даже не придется её искать, а останется лишь исправить ошибку.

Так же эта строка поможет избежать неявных ошибок и в других ситуациях. В частности, при обращении к другим приложениями(Word, Outlook и т.д.). Например, в Excel применяются именованные константы для многих задач. Одна из распространенных — поиск последней ячейки в столбце: llast = Cells(Rows.Count, 1).End(xlUp).Row
здесь xlUp является именованной константой, значение которой равно числу: -4162. В других приложениях такой же подход. Это избавляет от необходимости помнить на память все значения констант и обращаться к ним при помощи intellisense. Но действуют эти константы исключительно внутри своего приложения(можете обратить внимание, у Excel константы начинаются с xl, а у Word — с wd). И т.к. объявлены эти константы в других приложениях — Excel про них не знает(как и другие приложения не знают про константы Excel). Для примера возьмем простой и рабочий код замены в Word:

    Dim wdDoc As Object
    Set wdDoc = objWordApp.ActiveDocument
    With wdDoc.Range.Find
        .Text = "привет"
        .Replacement.Text = "привет"
        .wrap = wdFindContinue
        .Execute Replace:=wdReplaceAll
    End With

Где wdFindContinue для Word-а равно 1, а wdReplaceAll = 2. Но это происходит только при выполнении изнутри самого Word-а(или при раннем связывании через ToolsReferences. Подробнее про это можно почитать в статье: Как из Excel обратиться к другому приложению).

Если же скопировать и выполнять данный код из Excel, то работать он будет не так как задумали. Дело в том, что Вы считаете, что Excel работает с обозначенными константами(wdFindContinue, wdReplaceAll) наравне с Word-ом. Но Excel на самом деле про них ничего не знает. И если директива Option Explicit будет отключена, то Excel просто назначает им значение по умолчанию — Empty. Которое преобразуется в 0. А это совсем иной поиск получается, т.к. должны быть значения 1 и 2. А если бы Option Explicit была включена, то Excel выделил бы их и указал, что они не объявлены. И тогда можно было бы сделать либо так:

    Dim wdDoc As Object
    Const wdFindContinue As Long = 1
    Const wdReplaceAll As Long = 2
    Set wdDoc = objWordApp.ActiveDocument
    With wdDoc.Range.Find
        .Text = "привет"
        .Replacement.Text = "привет"
        .wrap = wdFindContinue
        .Execute Replace:=wdReplaceAll
    End With

либо так(что удобнее, на мой взгляд):

    Dim wdDoc As Object
    Set wdDoc = objWordApp.ActiveDocument
    With wdDoc.Range.Find
        .Text = "привет"
        .Replacement.Text = "привет"
        .wrap = 1
        .Execute Replace:=2
    End With

Так что думаю, не стоит недооценивать значимость строки Option Explicit при написании кодов. В довершение хотелось бы Вас обрадовать, что вписывание данной строки в начало каждого модуля можно сделать автоматическим: поставить в опциях редактора галочку: ToolsOptions-вкладка EditorRequire Variable Declaration. Теперь во всех новых созданных модулях строка Option Explicit будет создаваться самим редактором VBA автоматически. К сожалению, в уже имеющихся модулях Вам придется проставить данную строку самим вручную. Но это того стоит, поверьте.

Так же см.:
Что такое переменная и как правильно её объявить?


Статья помогла? Поделись ссылкой с друзьями!

  Плейлист   Видеоуроки


Поиск по меткам

Access
apple watch
Multex
Power Query и Power BI
VBA управление кодами
Бесплатные надстройки
Дата и время
Записки
ИП
Надстройки
Печать
Политика Конфиденциальности
Почта
Программы
Работа с приложениями
Разработка приложений
Росстат
Тренинги и вебинары
Финансовые
Форматирование
Функции Excel
акции MulTEx
ссылки
статистика

I am a long time avid Excel user but am just starting to learn VBA. I am using the following code but am getting an error when I try to run Sub test:

Compile Error:Variable not defined

Can you help me figure out what is wrong?

Option Explicit

Function toFarenheit(degrees)
    toFarenheit = (9 / 5) * degrees + 32
End Function

Function toCentigrade(degrees)
    toCentigrade = (5 / 9) * degrees - 32
End Function

Sub test()
    answer = toCentigrade(55)
    MsgBox answer    
End Sub

RubberDuck's user avatar

RubberDuck

11.4k4 gold badges47 silver badges95 bronze badges

asked Dec 29, 2014 at 19:43

Alyss's user avatar

You have Option Explicit turn on which means you must declare your variables before using them.

In Sub test, you are missing a declaration for answer. Adding this should fix it:

Sub test()
    Dim answer As Variant
    answer = toCentigrade(55)
    MsgBox answer    
End Sub

Edit

Since you are new to VBA, you might want to consider typing both your variables and function returns. You don’t have to do this (and everything will be treated as a Variant), but it is good practice.

If you type everything properly, your example would become:

Option Explicit

' Accept a double value and return a double type value.
Function toFarenheit(degrees As Double) As Double
    toFarenheit = (9 / 5) * degrees + 32
End Function

Function toCentigrade(degrees As Double) As Double
    toCentigrade = (5 / 9) * degrees - 32
End Function

Sub test()
    ' Variable type matches what the function will return.
    Dim answer As Double
    answer = toCentigrade(55)
    MsgBox answer    
End Sub

answered Dec 29, 2014 at 19:52

Jason Faulkner's user avatar

Jason FaulknerJason Faulkner

6,2432 gold badges28 silver badges33 bronze badges

3

I tested this to convert to farenheit

The function is as follows

Function ToFarenheit(Degrees As Double)

ToFarenheit = (9 / 5) * Degrees + 32

End Function

The sub is as follows

Sub TestFunction()

MsgBox ToFarenheit(0)

End Sub

answered Dec 29, 2014 at 19:52

bilbo_strikes_back's user avatar

1

При выполнении макросов Excel могут возникнуть ошибки, которые в VBA делят на три категории:

  • Ошибки компиляции
  • Ошибки выполнения
  • Логические ошибки (баги)

Далее мы поговорим о каждом из трёх типов ошибок VBA подробно.

Содержание

  1. Ошибки компиляции
  2. Ошибки выполнения
  3. Перехват ошибок выполнения
  4. Логические ошибки

Ошибки компиляции

Компилятор VBA рассматривает ошибки компиляции как недопустимые и выделяет их в коде ещё до того, как дело дойдёт до запуска макроса.

Если при написании кода допущена синтаксическая ошибка, то редактор VBA сигнализирует об этом немедленно: либо при помощи окна с сообщением, либо выделяя ошибку красным цветом, в зависимости от статуса режима Auto Syntax Check.

Примечание: При включённом режиме Auto Syntax Check каждый раз, при появлении в редакторе Visual Basic во введённом коде синтаксической ошибки, будет показано соответствующее сообщение. Если же этот режим выключен, то редактор VBA продолжит сообщать о синтаксических ошибках, просто выделяя их красным цветом. Опцию Auto Syntax Check можно включить/выключить в меню Tools > Options редактора Visual Basic.

В некоторых случаях ошибка компиляции может быть обнаружена при выполнении компиляции кода, непосредственно перед тем, как макрос будет выполнен. Обычно ошибку компиляции несложно обнаружить и исправить, потому что компилятор VBA даёт информацию о характере и причине ошибки.

Ошибки в Excel VBA

Например, сообщение «Compile error: Variable not defined» при попытке запустить выполнение кода VBA говорит о том, что происходит попытка использовать или обратиться к переменной, которая не была объявлена для текущей области (такая ошибка может возникнуть только если используется Option Explicit).

Ошибки выполнения

Ошибки выполнения возникают в процессе выполнения кода и приводят к остановке выполнения программы. Этот тип ошибок VBA, как правило, также не сложно обнаружить и исправить, так как сообщается информация о характере ошибки и место в коде, где произошла остановка.

Примером такой ошибки может служить попытка выполнить деление на ноль. В результате будет показано сообщение «Run-time error ’11’: Division by zero«.

Ошибки в Excel VBA

В зависимости от структуры проекта VBA, может быть предложено выполнить отладку кода (как показано на рисунке ниже). В этом случае при нажатии на кнопку Debug (в окне сообщения о необходимости отладки) будет выделена цветом строка кода, которая стала причиной ошибки VBA.

Ошибки в Excel VBA

Получив такое сообщение и видя выделенную строку кода, как в приведённом выше примере, обнаружить причину ошибки будет совсем не сложно.

В случае если код сложнее, чем в нашем примере, то, чтобы получить больше информации о причине возникновения ошибки VBA, можно проверить значения используемых переменных. В редакторе VBA для этого достаточно навести указатель мыши на имя переменной, или можно открыть окно отслеживания локальных переменных (в меню редактора View > Locals Window).

Коды различных ошибок выполнения расшифрованы на сайте Microsoft Support (на английском). Наиболее часто встречающиеся ошибки VBA перечислены в этой таблице:

5 Недопустимый вызов процедуры (Invalid procedure call)
7 Недостаточно памяти (Out of memory)
9 Индекс вне заданного диапазона (Subscript out of range)

Эта ошибка возникает при попытке обратиться к элементу массива за пределами заданного размера массива – например, если объявлен массив с индексами от 1 до 10, а мы пытаемся обратиться к элементу этого же массива с индексом 11.

11 Деление на ноль (Division by zero)
13 Несоответствие типа (Type mismatch)

Эта ошибка возникает при попытке присвоить переменной значение не соответствующего типа – например, объявлена переменная i типа Integer, и происходит попытка присвоить ей значение строкового типа.

53 Файл не найден (File not found)

Иногда возникает при попытке открыть не существующий файл.

Перехват ошибок выполнения

Не все ошибки выполнения бывают вызваны недочётами в коде. Например, ошибки VBA не удастся избежать, если для работы макроса необходимо открыть файл с данными, а этого файла не существует. В таких случаях признаком профессионализма будет перехват ошибок и написание кода VBA, который будет выполняться при их возникновении. Таким образом, вместо неприятных сбоев будет происходить изящное завершение работы макроса.

Для того, чтобы помочь справиться с возникающими ошибками, VBA предоставляет разработчику операторы On Error и Resume. Эти операторы отслеживают ошибки и направляют выполнение макроса в специальный раздел кода VBA, в котором происходит обработка ошибки. После выполнения кода обработки ошибки, работа программы может быть продолжена с того места, где возникла ошибка, или макрос может быть остановлен полностью. Далее это показано на примере.

'Процедура Sub присваивает переменным Val1 и Val2 значения,
'хранящиеся в ячейках A1 и B1 рабочей книги Data.xlsx расположенной в каталоге C:Documents and Settings

Sub Set_Values(Val1 As Double, Val2 As Double)

   Dim DataWorkbook As Workbook

   On Error GoTo ErrorHandling

      'Открываем рабочую книгу с данными

      Set DataWorkbook = Workbooks.Open("C:Documents and SettingsData")

      'Присваиваем переменным Val1 и Val2 данные из рабочей книги DataWorkbook

      Val1 = Sheets("Лист1").Cells(1, 1)
      Val2 = Sheets("Лист1").Cells(1, 2)

      DataWorkbook.Close

   Exit Sub

ErrorHandling:

   'Если файл не найден, предлагаем пользователю разместить его в
   'нужном месте и продолжить работу

   MsgBox "Рабочая книга не найдена! " & _
      "Пожалуйста добавьте книгу Data.xlsx в каталог C:Documents and Settings и нажмите OK."

   Resume

End Sub

В этом коде производится попытка открыть файл Excel с именем Data. Если файл не найден, то пользователю будет предложено поместить этот файл в нужную папку. После того, как пользователь сделает это и нажмёт ОК, выполнение кода продолжится, и попытка открыть этот файл повторится. При желании вместо попытки открыть нужный файл, выполнение процедуры Sub может быть прервано в этом месте при помощи команды Exit Sub.

Логические ошибки

Логические ошибки (или баги) возникают в процессе выполнения кода VBA, но позволяют ему выполняться до самого завершения. Правда в результате могут выполняться не те действия, которые ожидалось, и может быть получен неверный результат. Такие ошибки обнаружить и исправить труднее всего, так как компилятор VBA их не распознаёт и не может указать на них так, как это происходит с ошибками компиляции и выполнения.

Например, при создании макроса в процедуре случайно были просуммированы не те переменные, которые требовалось просуммировать. Результат будет ошибочным, но макрос будет продолжать выполняться до завершения.

Редактор Excel VBA предоставляет набор инструментов отладки, которые помогут найти и исправить логические ошибки в коде VBA. В данной статье мы не будем рассматривать подробно эти инструменты. Любознательный пользователь может найти обзор инструментов отладки VBA на сайте Microsoft Help & Support (на английском).

Оцените качество статьи. Нам важно ваше мнение:

Permalink

Cannot retrieve contributors at this time

title keywords f1_keywords ms.prod ms.assetid ms.date ms.localizationpriority

Variable not defined

vblr6.chm1011191

vblr6.chm1011191

office

4d8fdcc2-e4a9-7eb5-e0d4-f7a8e47b7431

06/08/2017

high

You use the Option Explicit statement to protect your modules from having undeclared variables and to eliminate the possibility of inadvertently creating new variables when typographical errors occur. This error has the following cause and solution:

  • You used an Option Explicit statement to require the explicit declaration of variables, but you used a variable without declaring it. Explicitly declare the variable, or change the spelling of the variable to match that of the intended variable.

For additional information, select the item in question and press F1 (in Windows) or HELP (on the Macintosh).

[!includeSupport and feedback]

 

nicex

Пользователь

Сообщений: 167
Регистрация: 26.07.2015

#1

12.07.2019 15:15:57

Добрый день!, выдает ошибку Compile error: variable not defined

Код
 For i = 1 To Cells(Rows.Count, "D").End(xlUp).Row

       If Cells(i, 7) = "TNK" Or Cells(i, 7) = "RST" Or Cells(i, 7) = "TY" Then Cells(i, 10) = "SS"
 Next



 Dim i As Long
 Dim iLastRow As Long
 iLastRow = Cells(Rows.Count, "B").End(xlUp).Row

  For i = iLastRow To 1 Step -1
    If Cells(i, 7) = 1 And Cells(i, 8) < 2500 Then Rows(i).ClearContents
  Next

Я поменял местаим части кода

Код
 Dim i As Long
 Dim iLastRow As Long
 iLastRow = Cells(Rows.Count, "D").End(xlUp).Row

   For i = iLastRow To 1 Step -1
  
        If Cells(i, 7) = "TNK" Or Cells(i, 7) = "RST" Or Cells(i, 7) = "TY" Then Cells(i, 10) = "SS"
   Next



 iLastRow = Cells(Rows.Count, "B").End(xlUp).Row

  For i = iLastRow To 1 Step -1
    If Cells(i, 7) = 1 And Cells(i, 8) < 2500 Then Rows(i).ClearContents
  Next

Подскажите корректно макрос будет работать ?

 

Nordheim

Пользователь

Сообщений: 3154
Регистрация: 18.04.2017

У вас таблица заполнена не полностью? почему в двух циклах последняя заполненная строка ищется по разным столбцам?

Изменено: Nordheim12.07.2019 15:25:00

«Все гениальное просто, а все простое гениально!!!»

 

nicex

Пользователь

Сообщений: 167
Регистрация: 26.07.2015

Nordheim, это только часть макроса

 

Sanja

Пользователь

Сообщений: 14837
Регистрация: 10.01.2013

#4

12.07.2019 15:42:43

Цитата
nicex написал: Подскажите корректно макрос будет работать ?

А самому попробовать?  

Согласие есть продукт при полном непротивлении сторон.

 

Nordheim

Пользователь

Сообщений: 3154
Регистрация: 18.04.2017

#5

12.07.2019 15:49:14

Цитата
nicex написал:
это только часть макроса

Я вижу, это не ответ на вопрос, если нужна последняя строка диапазона, то  я не вижу смысла в двух циклах,
да и Select Case , как по мне, в данном случае предпочтительней.

«Все гениальное просто, а все простое гениально!!!»

 

nicex

Пользователь

Сообщений: 167
Регистрация: 26.07.2015

Sanja, я попробовал, работает, но проблема проверить результат, опасаюсь что в макросе что то не корректно обрабатывается, поэтому хочу понять не приведет ли такая замена на обум к ошибкам

Nordheim, мои возможности только методом тыка адаптировать готовый код

 

Nordheim

Пользователь

Сообщений: 3154
Регистрация: 18.04.2017

#7

12.07.2019 16:02:16

Цитата
nicex написал:
мои возможности только методом тыка адаптировать готовый код

Вы не знаете как ответить на вопрос

Цитата
Nordheim написал:
почему в двух циклах последняя заполненная строка ищется по разным столбцам?

или не хотите, меня не интересовало полный это макрос или часть, я это и так вижу.

Цитата
nicex написал:
мои возможности только методом тыка адаптировать готовый код

про ваши методы я так же не спрашивал. Вопрос тут в таком случае такой, а вы уверены что код вообще работает правильно, коли вы не знаете почему определение последней заполненной строки производится по разным столбцам?

«Все гениальное просто, а все простое гениально!!!»

 

nicex

Пользователь

Сообщений: 167
Регистрация: 26.07.2015

Nordheim, я объединил два разных макроса. перед второй частью макроса :

////// iLastRow = Cells(Rows.Count, «B»).End(xlUp).Row

 For i = iLastRow To 1 Step -1
   If Cells(i, 7) = 1 And Cells(i, 8) < 2500 Then Rows(i).ClearContents
 Next /////

происходит перестановка колонок и еще какие то замены и тп и тд

 

Sanja

Пользователь

Сообщений: 14837
Регистрация: 10.01.2013

Ошибка исчезла? Значит решение задачи, вынесенной в название Темы получено. Все остальное ЭТОЙ темы не касается.
Вы сначала разберитесь, что Вы хотите от этого макроса, а уже потом задавайте вопросы, конкретные, в других темах

Согласие есть продукт при полном непротивлении сторон.

 

Jack Famous

Пользователь

Сообщений: 10382
Регистрация: 07.11.2014

OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome

#10

12.07.2019 16:41:01

Цитата
nicex: Compile error: variable not defined

объявите переменную. Для того, чтобы в будущем этого избежать, прочтите

инструкцию

Прикрепленные файлы

  • 1.png (8.23 КБ)

Изменено: Jack Famous12.07.2019 16:41:33

Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄

 

nicex

Пользователь

Сообщений: 167
Регистрация: 26.07.2015

Jack Famous, спасибо

Sanja, как изменить тему на: Я поменял местаим части кода будет ли корректно макрос работать ?

 

vikttur

Пользователь

Сообщений: 47199
Регистрация: 15.09.2012

Такая ошибка может возникнуть в тысячах разных кодов.
Как назовем тему, пмощники?

 
название темы:

что значит сообщение Compile error: variable not defined при попытке выполнить макрос?

ответ:

в сообщении все сказано: Ошибка компилятора: неопределенная переменная!
эта  значит что в начале модуля есть инструкция Option Explicit которая требует обьявления ЛЮБОЙ переменной прежде, чем она будет использована в коде

решение:

1. удалите строку Option Explicit
или
2.напишите Option Explicit Off
или
3. обьявите перменную (Din переменная as…) раньше, чем обращаетесь к ней где-либо в коде
удачи!

Программисты — это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!

 

RAN

Пользователь

Сообщений: 7081
Регистрация: 21.12.2012

Вить, коды-то разные, причина одна.
И название ничем не хуже

этого

, или

этого

 

vikttur

Пользователь

Сообщений: 47199
Регистрация: 15.09.2012

Андрей, одна в Курилке, по второй более-менее понятно по названию.
А по этой… Вчитываться во все темы нет возможности, вижу обсуждение кода… поэтому и спрашиваю — как переименовать. Если не надо — оставим.

 

Dima S

Пользователь

Сообщений: 2063
Регистрация: 01.01.1970

#16

13.07.2019 01:53:01

Цитата
Ігор Гончаренко написал:
(Din переменная as…)

Dim

  • #1

This is my first post. Greetings from Athens, TX!

I’ve used Excel for many years, but finally am learning VBA, using Excel Progamming for Dummies by John Walkenbach. Excel is version 2000.

I’ve searched extensively on Google and on the MrExcel site for the solution to my problem, but still haven’t found it . Any direction would be most appreciated.

I’m trying to execute the examples in the book, and have gotten the error message «Compile error: Variable not defined» with «MyString =» highlighted with several of the examples. Could someone please tell me where I’m going astray?

Following is the latest subroutine I typed into the module, from page 124:

Option Explicit

Sub GetLength()
MyString = «Hello World»
StringLength = Len(MyString)
MsgBox StringLength
End Sub

Thank you for your help!

Mark Carlson

Can a formula spear through sheets?

Use =SUM(January:December!E7) to sum E7 on all of the sheets from January through December

  • #2

Try

Code:

Sub GetLength()
Dim MYstring As String
MYstring = "Hello World"
StringLength = Len(MYstring)
MsgBox StringLength
End Sub
  • #3

Thanks, but the same error message is here, and «StringLength =» is still highlighted.

Mark

  • #4

Welcome to the board.

Well, yes. When you googled, did you search on the term «option explicit»? That forces variable declarations.

Code:

Option Explicit
 
Sub GetLength()
    dim strMyString as string, lngStringLength as long
    strMyString = "Hello World"
    lngStringLength = Len(strMyString)
    MsgBox lngStringLength
End Sub

Last edited: May 27, 2008

  • #5

Oops!

Code:

Sub GetLength()
Dim MYstring As String, StringLength As Integer
MYstring = "Hello World"
StringLength = Len(MYstring)
MsgBox StringLength
End Sub

The reason that you are getting these errors is that you have set ‘Require variable declaration’ in Tools > Options which is a very good idea. Shame Walchenbach et al. didn’t think of that!

  • #6

Greg,

I didn’t Google «Option Explicit» (OE). The book suggested using OE as a matter of course. I’ve seen that stated several other places while trying to figure this out.

Thanks, Mark

  • #8

Declare your variables. (= appear in a DIM statement prior to usage)

  • #9

Greg,

I’m afraid I’m not quite getting this. Do you mean I need an «=» in the dim statement? Also in your signature you have the hint about CODE tags. Would that be 010, 020, etc at the start of the lines?

Have a great evening!

Thanks again, Mark

RoryA

RoryA

MrExcel MVP, Moderator
  • #10

Option Explicit requires you to declare all your variables. In your code, you use two variables, MyString and StringLength, so you have to declare them:

Code:

Dim MyString As String, StringLength as Long

(note, you don’t have to declare them as having a specific type/interface, but it’s good practice to do so where possible)
The code tags are what I used above to make the code line stand out.
Regards,
Rory

Joe4

Rijnsent

Отлов ошибок и отладка кода VBA

Очень часто начинающие работать в VBA сталкиваются с различными ошибками, которые выдает код в момент выполнения. Если не знать как поступить в данном случае – то очень сложно будет исправить код быстро, а то и вообще невозможно будет определить причину ошибки без помощи более «продвинутых» пользователей. Новички зачастую делают правки наугад, что может порождать иные ошибки, а это в свою очередь не только затрудняет поиск первоначальной ошибки, но и может привести к невозможности исправить код вообще. Поэтому в этой статье я решил описать как производить отладку кода и определять ошибки.
Чтобы описанное в статье можно было сразу опробовать в практике советую скачать файл пример:

  Пример таблицы и кода (35,5 KiB, 1 078 скачиваний)


Что будет рассмотрено:

  • Способы отладки кода в момент появления ошибки
  • Использование окон Locals и Watches для отладки
  • Пошаговая отладка кода — что это такое, как и когда применять
  • Ошибок нет, но код все равно не выполняется

Помимо этого в конце статьи можно скачать файл с кодами ошибок VBA и их расшифровками.

Исходные данные
Допустим, имеется простая таблица

И код, который должен пройтись по каждой строке таблицы, перемножить цену (столбец
Цена) на количество (столбец Продажи шт), просуммировать перемноженные данные и вывести результирующую сумму в ячейку В17:

Option Explicit Sub PrimitiveCode() Dim lr As Long, dblSumm As Double, dblIncr As Double ‘цикл от первой строки таблицы до последней For lr = 1 To 14 ‘перемножение Цены на Количество (C*E) dblIncr = Cells(l, 3).Value * Cells(lr, 5).Value ‘прибавление результата к переменной общей суммы dblSumm = dblSumm + dblIncr Next ‘выводим результат в ячейку B17 Cells(17, 2).Value = dblSumm End Sub

Option Explicit

Sub PrimitiveCode()

    Dim lr As Long, dblSumm As Double, dblIncr As Double

    ‘цикл от первой строки таблицы до последней

    For lr = 1 To 14

        ‘перемножение Цены на Количество (C*E)

        dblIncr = Cells(l, 3).Value * Cells(lr, 5).Value

        ‘прибавление результата к переменной общей суммы

        dblSumm = dblSumm + dblIncr

    Next

    ‘выводим результат в ячейку B17

    Cells(17, 2).Value = dblSumm

End Sub


 
Отладка кода в момент появления ошибки
Если посмотреть на код выше, то опытный программист VBA сразу поймет, что в таком виде код работать не будет – не выполнится и одна строка. Сразу появится ошибка:

Ошибка означает, что внутри кода есть переменная, которая ранее не была объявлена.
Сама переменная, которую VBA считает не объявленной будет выделена:

Подробнее об этой ошибке и её причинах можно почитать в статье:
Variable not defined или что такое Option Explicit и зачем оно нужно?
Если кратко, то переменной
l нет среди объявленных переменных(Dim l As) и мы не можем её использовать. В данном случае это опечатка и там должна быть lr, а не l. Исправляем переменную и код будет выглядеть так:

Sub PrimitiveCode() Dim lr As Long, dblSumm As Double, dblIncr As Double ‘цикл от первой строки таблицы до последней For lr = 1 To 14 ‘перемножение Цены на Количество (C*E) dblIncr = Cells(lr, 3).Value * Cells(lr, 5).Value ‘прибавление результата к переменной общей суммы dblSumm = dblSumm + dblIncr Next ‘выводим результат в ячейку B17 Cells(17, 2).Value = dblSumm End Sub

Sub PrimitiveCode()

    Dim lr As Long, dblSumm As Double, dblIncr As Double

    ‘цикл от первой строки таблицы до последней

    For lr = 1 To 14

        ‘перемножение Цены на Количество (C*E)

        dblIncr = Cells(lr, 3).Value * Cells(lr, 5).Value

        ‘прибавление результата к переменной общей суммы

        dblSumm = dblSumm + dblIncr

    Next

    ‘выводим результат в ячейку B17

    Cells(17, 2).Value = dblSumm

End Sub

С виду код теперь выполнен правильно и ошибок вызывать не должен. Однако, если его попытаться выполнить опять получим ошибку – на этот раз ошибку типов данных(Type Mismatch):

В момент появления главное нажать
Debug, а не End (если будет желание прочитать про тип ошибки подробнее – можно еще нажать Help, текст будет на английском). VBA подсветит желтым строку, вычисления или операции в которой вызывают ошибку:

Теперь самый важный этап – необходимо определить причину ошибки. С виду все хорошо – одна ячейка перемножается на другую. Без опыта сложно сходу понять, что это ошибка типов данных, хоть VBA прямо об этом говорит(Type Mismatch – в переводе «Несовпадение типов»). Поэтому самое надежное в этом случае – это определить значение каждой составляющей той строки, в которой возникла ошибка. В случае с кодом выше можно воспользоваться двумя методами:

  1. Навести курсор мыши на любую переменную(dblSum, lr) и посмотреть всплывающую подсказку, которая показывает имя переменной и её текущее значение:

    После этого переходим на лист с таблицей и смотрим, какое значение в ячейке первой строки третьего столбца(Cells(1,3)). Там значение
    Закуп цена, что явно не является числом. Следовательно перемножить его нельзя, т.к. это текст. Отсюда и ошибка типов – с текстом нельзя производить математические операции. Для вычислений предполагается в данном случае числовой тип данных(Integer,Long,Double).
  2. Узнать сразу значение ячейки Cells(lr, 3).Value и ячейки Cells(lr, 5).Value. Наведение курсора мыши в данном случае не даст результата. Как правило наведение курсора мыши не имеет эффекта если это не объявленные как переменные объекты (как в этом случае — Cells). Такие объекты не всегда могут быть вычислены в памяти в момент отладки. Поэтому чтобы просмотреть значение ячейки сначала необходимо отобразить окно Immediate(отобразить можно сочетанием клавиш Ctrl+G или через меню ViewImmediate Window). Затем скопировать полностью нужную переменную(Cells(i, 3).Value) и в окне Immediate написать:
    ?
    и после вопр.знака вставить скопированное. Должно получиться:
    ?Cells(i, 3).Value
    И нажать
    Enter. Строкой ниже в этом окне будет выведено значение для объекта(если оно может быть получено):

    По сути результат будет как и в первом примере – мы увидим, что в ячейке текст. Чем второй метод лучше первого? Тем, что таким образом можно сразу получить значение, не переходя на лист и не выискивая нужный номер строки. Ведь это в примере он равен 1, в реальности же строка может быть и 24451.


 
Окна Locals и Watches
Так же для отслеживания значений переменных очень удобно использовать окно
Locals и окно Watches.
Окно Locals
Окно
Locals отображает все локальные переменные, задействованные в выполняемой в настоящий момент процедуре:

Как видно в этом окне отображается имя переменной, её тип и значение. Все хорошо, но в этом окне отображаются исключительно локальные переменные, объявленные на уровне модуля. Переменных других модулей, объявленные как Public и используемые в текущей процедуре там не отображаются. Подробнее про видимость переменных можно узнать в статье:
Что такое переменная и как правильно её объявить?

Окно Watches
Окно
Watches представляет большую ценность – в это окно можно просто «перетащить» нужную переменную или объект и в этом окне будут отражены все данные об имени переменной, её типе и текущем значении:

Теперь рассмотрим чуть подробнее как перетаскивать в это окно данные. На примере кода выше:

  • Выделяем Cells(i, 3).Value
  • Не снимая выделения наводим курсор мыши на это выделение
  • Зажимаем левую кнопку мыши и не отпуская её переносим курсор в любое место окна Watches

Все, данные по переменной загружены и доступны для просмотра. По сути все умеют это делать — процесс очень схож с обычным перемещением файлов и папок по рабочему столу. Выделили и с зажатой левой кнопкой мыши перенесли в нужное место.
В чем еще один плюс этого окна – в этом окне можно оставлять эти значения и просматривать в моменты пошаговой отладки только занесенные в это окно переменные(про пошаговую отладку будет рассказано ниже). Если вдруг какая-то переменная/объект стали не нужны для постоянного отслеживания их данных – можно удалить их из окна Watches, чтобы не мешалась. Для этого выделяем переменную-правая кнопка мыши –
Delete Watch. Так же можно поиграть с иными пунктами, наибольший интерес из которых на мой взгляд, представляет пункт Edit Watch. После его нажатия появится окно

Самые основные пункты в этом окне, важные для отладки:

  • Break Then value Changes. Если его установить, VBA будет отслеживать значение этой переменной и останавливать код при любом изменении значения переменной. Это может пригодится для отслеживания значений в циклах
  • Break Then value Is True – пункт пригодится для переменных с типом Boolean или для логических выражений. Как только переменная или результат выражения примет значение True – код будет остановлен на этой строке.
    Например, необходимо остановить код, если номер строки будет равен 10(т.е. переменная lr примет значение 10). Тогда выражение будет иметь вид:

If lr = 10 Then ‘код End if

If lr = 10 Then

‘код

End if


Тогда надо будет выделить в строке
If lr = 10 Then само условное выражение lr = 10, перенести её в окно Watches, выделить строку в окне Watches с этим выражением, нажать правую кнопку мыши и выбрать Edit Watch. Выбрать в окне Break Then value Is True. Теперь как только переменная lr достигнет значения 10(т.е. обрабатываться будет 10-я строка таблицы) – код остановится и строка с выражением будет выделена желтым. Можно будет проанализировать другие переменные или продолжить выполнение кода в пошаговом режиме(см.далее).



 
Пошаговая отладка кода
После знакомства с отладкой кода при возникновении ошибки работать с пошаговой отладкой будет проще.
Что такое вообще пошаговая отладка?
Это просмотр этапов выполнения кода строка за строкой.

Для чего это может быть нужно?

  • Чтобы проанализировать чужой код и понять более точно, что он делает изнутри, а не только увидеть результат его выполнения
  • Если вы начинающий программист и часто используете макрорекордер(записываете макросы) — то пошаговая отладка поможет понять какое действия выполняет каждая строка. Это поможет быстрее научиться понимать код и убирать из него лишнее, а так же совмещать различные коды
  • Если внутри кода есть ошибка логики выполнения. Это, пожалуй, самая сложная ошибка, т.к. в этом случае VBA не останавливает работу и не говорит об ошибке. Код выполняется без ошибок, но результат не такой, как ожидалось. Это означает, что либо какой-то переменной назначается не то значение, либо какое-то условие неверно или выполняется не в тот момент, в который должно. В общем по сути это ошибка разработчика, не приводящая к ошибкам синтаксиса или типов, которые VBA может отследить.

Как делать пошаговую отладку? Все просто: устанавливаете курсор в любом месте внутри кода и нажимаете клавишу F8 (либо выбрать в меню DegubStep Into). Теперь при каждом нажатии клавиши F8 код будет выполнять одну строку кода за другой в той очередности, в которой они расположены в процедуре. Если внутри процедуры будет вызов второй процедуры или функции – код пошагово выполнит и её и затем вернется в основную процедуру.
Так же хочу привести еще пару сочетаний клавиш, которые удобно применять при пошаговой отладке:

  • Shift+F8(DegubStep Over) — выполнение вложенной функции/процедуры без захода в неё. Если внутри основной процедуры или функции выполняется другая процедура или функция и Вы уверены, что она работает правильно — просматривать пошагово весь код вложенной процедуры/функции не имеет смысла. Чтобы вложенная процедура/функция выполнилась без пошагового просмотра надо просто нажать указанное сочетание клавиш тогда, когда строка вызова вложенной процедуры/функции будет подсвечена желтым
  • Ctrl+Shift+F8(DegubStep Out) — завершение вложенной функции/процедуры и выход в основную с остановкой. Если все же перестарались и перешли в пошаговый проход вложенной функции(или сделали это специально, но посмотрели все, что надо) — то нажимаете это сочетание и код быстро выполнить вложенную функцию, перейдет в основную и остановится для дальнейшей пошаговой отладки
  • Ctrl+F8(DegubRun to Cursor) — выполнение процедуры до строки, в которой на данный момент установлен курсор

Точки останова
Но куда чаще бывает нужно не просто весь код пройти пошагово, а начать пошаговое выполнение только начиная с какой-либо одной строки, чтобы не мотать строк 40 кода(да еще с циклами) ради достижения одной какой-то строки. Еще точки останова очень полезны при отладке событийных процедур(вроде Worksheet_Change, Worksheet_BeforeDoubleClick, событий элементов форм и т.п.), т.к. они в большинстве своем содержат аргументы и выполнить по F8 их просто невозможно и выполняются они только при наступлении самого события, которые они призваны обработать.
Чтобы дать понять VBA на какой строке необходимо будет остановится необходимо установить курсор мыши в любое место нужной строки и нажать
F9 или DebugToggle Breakpoint. Строка будет выделена темно-красным цветом.
Это еще называется установкой
точки останова. Убрать точку останова можно так же, как она была установлена – F9 или DebugToggle Breakpoint. Так же точку основа можно установить с помощью мыши: для этого необходимо в области левее окна с кодом напротив нужной строки один раз щелкнуть левой кнопкой мыши:

Теперь можно запустить код любым удобным способом (в отладке это как правило делается клавишей F5 или с панели: RunRun Sub/UserForm). Как только код дойдет до указанной точки останова он остановится и строка будет подсвечена желтым. Дальше можно либо продолжить выполнение в пошаговом режиме(нажимая F8), либо(проверив значения нужных переменных и объектов) нажать опять F5 и код продолжит выполняться автоматически, пока не выполнится или не достигнет другой точки останова. Самих же точек останова может быть сколько угодно и расположены они могут быть в любой процедуре или функции.
Следует помнить, что после закрытия файла с кодом точки останова не сохраняются и при следующем открытии книги их необходимо будет установить заново, если это необходимо.



 
Ошибок нет, но код все равно не выполняется
Еще хочу добавить, что ошибки могут появляться не всегда, даже если они есть. Бывает и так, что код выполняется без ошибок, но однако либо выполняется не так, либо вообще ничего не делает. Как правило причин две:

  1. Логика кода построена неверно и ошибок VBA действительно не возникает. Но т.к. логика неверна — код выполняет не то, что от него ожидается. Решение одно — пошагово выполнить весь код и детально просмотреть всё, чтобы обнаружить в какой строке или строках нарушена логика
  2. Один из очень распространенных вариантов: в начале кода стоит обработчик ошибок On Error Resume Next и дальше обработчик не отменяется. Данный обработчик указывает VBA, что при возникновении ошибки её следует игнорировать и переходит к выполнению следующего оператора/строки. Таким образом ошибка хоть и возникает, но она пропускается и не показывается, а выполнение кода продолжается как ни в чем не бывало. Однако как правило одна ошибка влечет другую и третью и т.д. и может получиться так, что все строки после первой ошибочной станут так же ошибочными и как следствие не выполнятся. Данный оператор будет применяться либо до конца процедуры, либо до тех пор, пока в коде не будет поставлен иной обработчик ошибок:
    On Error GoTo
    Метка — переход выполнения кода к указанной метке(Метка).
    On Error GoTo 0 — по сути отменяет условный переход при возникновении ошибок. Метка 0 считается обнулением переходов

Один из примеров того, для чего может применяться обработчик ошибок можно найти в статье: Как из Excel обратиться к другому приложению. Там данный обработчик необходим, чтобы проверить открыто ли уже приложение Word. Если открыто — то ошибка не возникнет. Если же закрыто — то будет ошибка. И этот момент как правило и отслеживается. Я расставил подробные комментарии в коде, чтобы было более понятно что к чему:

Sub Check_OpenWord() Dim objWrdApp As Object On Error Resume Next ‘необходимо, чтобы на первой же строке код не выдал ошибку при закрытом Word ‘пытаемся подключится к объекту Word Set objWrdApp = GetObject(, «Word.Application») ‘если Word закрыт — обязательно возникнет ошибка 429, ‘указывающая на то, что невозможно подключиться к объекту Word ‘при этом переменная objWrdApp будет равняться Nothing, т.к. значение не удалось присвоить If objWrdApp Is Nothing Then ‘так же можно использовать и такую строку: ‘If Err.Number = 429 Then ‘если ошибка 429 — значит Word не запущен — надо создавать новый ‘создаем новый экземпляр Set objWrdApp = CreateObject(«Word.Application») ‘делаем приложение видимым. По умолчанию открывается в скрытом режиме objWrdApp.Visible = True Else ‘приложение открыто — выдаем сообщение MsgBox «Приложение Word уже открыто», vbInformation, «Check_OpenWord» End If End Sub

Sub Check_OpenWord()

    Dim objWrdApp As Object

    On Error Resume Next ‘необходимо, чтобы на первой же строке код не выдал ошибку при закрытом Word

    ‘пытаемся подключится к объекту Word

    Set objWrdApp = GetObject(, «Word.Application»)

    ‘если Word закрыт — обязательно возникнет ошибка 429,

    ‘указывающая на то, что невозможно подключиться к объекту Word

    ‘при этом переменная objWrdApp будет равняться Nothing, т.к. значение не удалось присвоить

    If objWrdApp Is Nothing Then

    ‘так же можно использовать и такую строку:

    ‘If Err.Number = 429 Then ‘если ошибка 429 — значит Word не запущен — надо создавать новый

        ‘создаем новый экземпляр

        Set objWrdApp = CreateObject(«Word.Application»)

        ‘делаем приложение видимым. По умолчанию открывается в скрытом режиме

        objWrdApp.Visible = True

    Else

        ‘приложение открыто — выдаем сообщение

        MsgBox «Приложение Word уже открыто», vbInformation, «Check_OpenWord»

    End If

End Sub

Для чего вообще это нужно? Ведь можно создавать новый экземпляр. А дело в том, что не всегда правильно создавать новый — куда правильнее зачастую подключиться к ранее открытому, чем плодить новые экземпляры и захламлять диспетчер задач.
Тему обработки ошибок я здесь пока не раскрываю полностью, т.к. это не на один абзац. В одной из следующий статей постараюсь более подробно рассказать как и где их лучше применять и как правильно, а когда лучше вообще воздержаться от их использования.


Конечно, статья не описывает способы устранения ошибок — это просто невозможно. Только известных типов ошибок в VBA более 3 тысяч. Все их упоминать бессмысленно. Целью статьи было помочь начинающим найти строку с ошибкой и рассказать как производить отладку кода при необходимости. А все остальное придет с опытом. Однако на всякий случай я решил выложить файл Excel с описанием большей части ошибок, которые могут возникнуть. В файле указан номер ошибки, описание на английском и описание на русском. Причин ошибки может быть множество, поэтому нет однозначных рекомендаций по устранению каждой из них. Все зависит от данных и от самого кода.

  Ошибки VBA с описанием (152,0 KiB, 2 022 скачиваний)

Понравилась статья? Поделить с друзьями:
  • Vbe6ext olb ошибка
  • Vector 1550 carrier коды ошибок
  • Vba ошибка 2465
  • Van 139 ошибка valorant
  • Vba счетчик ошибок