Remkomplekty.ru

IT Новости из мира ПК
3 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Ошибка c4700 использована неинициализированная локальная переменная

Проклятие неинициализированных переменных

    Переводы, 1 февраля 2015 в 21:15

Позволять программистам использовать неинициализированные переменные — большая ошибка со стороны разработчиков языка. Такую оплошность легко совершить и тяжело отследить. Особенно при выполнении программы на разных платформах. И необходимости в этой особенности нет — переменная всегда должна иметь определенное значение.

Проблема

Локальные переменные, переменные-поля и т.п. являют собой неинициализированные переменные, т.е. в них будет записано ровно то, что было записано в отведенной под них памяти при объявлении. В C++ существуют различные правила для работы с неинициализированными переменными, инициализированными переменными и нуль-инициализированными переменными. Очень путанный механизм.

Учитывая частоту, с которой в коде появляются неинициализированные переменные, можно подумать, что отследить подобные ситуации в коде легко. Совсем нет. Да, конечно же, большая часть автоматически инициализируется нулем, если не указано иное. Однако так происходит не всегда. Например, в результате выполнения этого кода:

В результате выполнения этого кода у автора статьи всегда печатается False и 0 . Ошибок, связанных с утечкой памяти, можно избежать, используя valgrind .

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

Почему ноль?

Почему программа автоматически инициализирует переменную нулем? На самом деле, это делает не программа, а операционная система, которая просто не позволит приложению проникнуть в неинициализированную область памяти, такова природа этого защитного механизма. Если программа A отработала свое, и результаты ее работы остались где-то в памяти, то программа B не должна обнаружить их во время своей работы, а потому ядро самостоятельно очищает память. В частности, Linux прописывает в освободившуюся память нули.

LATOKEN, Москва, от 3500 до 5000 $

Естественно, нет никакого правила, чем заполнять память. Вероятно, OpenBSD делает это как-то иначе. Иначе чистит память и ArchLinux, запущенный в VirtualBox. Этим может заниматься не только операционная система — то же может проделать и другая программа, например. И если вдруг в область памяти, которую использует приложение, попадут какие-нибудь значения, изменить их сможет уже только сама эта программа.

Любопытно, что это стало одной из причин появления Heartbleed бага.

Решение

Язык просто не должен позволять использовать неинициализированные переменные. Необязательно нужно указывать конкретное значение — значение просто обязательно должно быть. Например, значением по умолчанию может стать все тот же ноль. Вне зависимости от того, как и в какой области видимости я создал данную переменную.

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

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

Автор статьи уверен, что уже в ближайшем стандарте C++ должны быть реализованы эти изменения. Превращение неинициализированных ранее переменных в инициализированные не повлияет на корректность выполнения ни одной программы. Такое нововведение будет полностью backwards compatible, и серьезно улучшит популярный язык.

error c4700 использована неинициализированная локальная переменная

неинициализированная локальная переменная «имя» используется uninitialized local variable ‘name‘ used

Локальная переменная имя был используется, то есть считывание, до того, как оно было назначено значение. The local variable name has been used, that is, read from, before it has been assigned a value. В C и C++ локальные переменные не инициализируются по умолчанию. In C and C++, local variables are not initialized by default. Неинициализированные переменные могут содержать любое значение, и их применение приводит к неопределенному поведению. Uninitialized variables can contain any value, and their use leads to undefined behavior. Предупреждение C4700 почти всегда указывает на ошибку, что может привести к непредсказуемым результатам или происходит аварийный сбой программы. Warning C4700 almost always indicates a bug that can cause unpredictable results or crashes in your program.

Читать еще:  Ошибка инициализации графической подсистемы

Чтобы устранить эту проблему, можно инициализировать локальные переменные, если они объявлены, или назначить значение к ним, прежде чем они используются. To fix this issue, you can initialize local variables when they are declared, or assign a value to them before they are used. Функция может использоваться для инициализации переменной, передаваемый в качестве ссылочного параметра, или если адрес передается как параметр-указатель. A function can be used to initialize a variable that’s passed as a reference parameter, or when its address is passed as a pointer parameter.

Пример Example

Этот пример приводит к возникновению ошибки C4700, когда переменные t, u и v используются, прежде чем они инициализируются и показывает, какие значения сборки мусора, которая может привести. This sample generates C4700 when variables t, u, and v are used before they are initialized, and shows the kind of garbage value that can result. Переменные x, y и z не вызвать предупреждение, так как они инициализируются перед использованием: Variables x, y, and z do not cause the warning, because they are initialized before use:

Когда этот код является выполнения, t, u и v не инициализированы и выходные данные для s будет непредсказуемым: When this code is run, t, u, and v are uninitialized, and the output for s is unpredictable:

Не могу запустить рабочий проект под Visual Studio 2013 из-за этой ошибки. Проект старый, делался еще под Visual Studio 6.0. Видимо, там выдавалось предупреждение вместо ошибки.

Переменных много. Может быть, все-таки можно обойти эту ошибку, не инициализируя их все?

1 ответ 1

В свойствах проекта — свойства конфигурации — С/С++ — создание кода — проверка безопасности — Отключить проверку безопасности (/GS-)

Здравствуйте. Я совсем новичок в программировании, никакого опыта не было. В общем компилятор показывает ошибку «error C4700: использована неинициализированная локальная переменная «a» и также «b». Не могу понять, что нужно сделать, укажите пожалуйста на ошибку.

  • Вопрос задан более трёх лет назад
  • 16829 просмотров

Вы складываете a и b, не присвоив им значений. В C/C++ в этом случае в переменных может оказаться произвольный мусор. Нужно писать double a = 0; double b = 0;

Компилятор не обнаруживает явно неинициализированную переменную

все компиляторы C, которые я пробовал, не будут обнаруживать неинициализированные переменные в приведенном ниже фрагменте кода. Тем не менее, случай здесь очевиден.

не беспокойтесь о функциональности этого фрагмента. Это не настоящий код, и я снял его для расследования этого вопроса.

С другой стороны, если я закомментировать tauxtrouve = value ; , Я «local variable ‘tauxtrouve’ used without having been initialized» предупреждение.

Я пробовал эти компиляторы:

  • GCC 4.9.2 с -стена -WExtra
  • Microsoft Visual C++ 2013 со всеми включенными предупреждениями

4 ответа:

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

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

EDIT: @Matthieu указывает, что с LLVM/clang анализ пути, необходимый для поиска использования неинициализированного значения, не усложняется по мере увеличения вложенности из-за нотации SSA, используемой IR.

это не так просто, как » -S -emit-llvm » как я надеялся, но я нашел выход SSA-нотации, который он описал. Я буду честен, я недостаточно знаком с LLVM IR, чтобы быть уверенным, но я поверю Матье на слово.

Читать еще:  Ошибка создания файла

итог: использовать clang С —analyze , или убедить кого-то, чтобы исправить gcc ошибка.

Да, это должно вызвать предупреждение об этой неинициализированной переменной, но это ошибка GCC. Приведенный там пример:

с диагнозом -O2 -W -Wall .

к сожалению, в этом году 10-летний юбилей этой ошибки!

этот ответ касается только GCC.

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

прежде всего,документация GCC на говорит:

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

предыдущие версии руководства GCC сформулировали это более явно. Вот отрывок из руководство для GCC 3.3.6:

эти предупреждения возможны только при оптимизации компиляции, поскольку они требуют информации о потоке данных, которая вычисляется только при оптимизации. Если вы не укажете-O, вы просто не получите эти предупреждения.

It кажется, текущая версия может дать некоторые предупреждения без неинициализированных переменных без -O , но вы все равно получите гораздо лучшие результаты с ним.

если я скомпилирую ваш пример с помощью gcc -std=c99 -Wall -O , Я:

(обратите внимание, что это с GCC 4.8.2, поскольку у меня нет 4.9.x установлен, но принцип должен быть таким же.)

так, что обнаруживает тот факт, что tauxtrouve инициализирован.

однако, если мы частично исправим код, добавив инициализатор для tauxtrouve (но не totaldiff ), то gcc -std=c99 -Wall -O принимает его без каких-либо предупреждений. Это, по-видимому, является экземпляром» ошибки», приведенной в haccks это.

есть некоторые вопросы относительно того, следует ли это действительно считать ошибкой: GCC не обещает поймать каждый возможный экземпляр неинициализированной переменной. Действительно, он не может сделать это с идеальной точностью, потому что это проблема останова. Поэтому такие предупреждения могут быть полезны, когда они работают, но отсутствие предупреждений не доказывает, что ваш код свободен от неинициализированных переменных! Они действительно не являются заменой для тщательной проверки Вашего собственного кода.

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

Майкл, я не знаю, какую версию Visual Studio 2013 Вы пробовали, но она, безусловно, устарела. Visual Studio 2013 Update 4 правильно выдает следующее сообщение об ошибке при первом использовании totaldiff :

вы должны рассмотреть возможность обновления рабочей среды.

C++: ошибка C4700 неинициализированная локальная переменная «» используется

Я выписал код, но я все время получаю сообщение об ошибке: «Использована неинициализированная локальная переменная Error C4700« zi_saptamana ». Ошибка C4700 неинициализированной локальной переменной« dar ». Я уже делал If/if-else/else, но я никогда не сталкивался с этой ошибкой. Я новичок в C++ и все еще учась.C++: ошибка C4700 неинициализированная локальная переменная «» используется

Ошибка довольно сам пояснительный. Я имею в виду, что из кода ‘zi_saptamana’ не был инициализирован код’ switch (zi_saptamana) ‘ – drescherjm

Какая часть« неинициализированной локальной переменной используется »неясно? –

Сообщение об ошибке ясно. Когда ‘switch (zi_saptamana)’, ‘zi_saptamana’ не инициализируется или не задается, его значение неопределенно. – songyuanyao

ответ

Вы объявляете zi_saptamana в int , но сразу после этого, не давая ему значение (без инициализации его), вы использование это в switch заявлении.

Обратите внимание, что значение zi_saptamana , которое является локальной переменной, не определено (оно может быть любым) перед его инициализацией. То же самое относится к dar .

Это то, что говорит вам компилятор.

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

Читать еще:  Как исправить ошибку 0xc0000001

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

Это не то, что «может быть что угодно», это то, что чтение неинициализированной переменной является неопределенным поведением, поэтому программа не имеет никакого смысла, и компилятор может что-либо сделать, включая удаление полностью выключайте. Вам не гарантируется просто получить случайную величину мусора (хотя вы * можете *). –

Ну, для всех, кого вы знаете или заботитесь, это может быть что угодно. Именно поэтому использование неинициализированной переменной было объявлено как неопределенное поведение, ISTM. –

Ну, компиляторы довольно агрессивно относятся к использованию неопределенного поведения в наши дни. И это может изменить другие части вашей программы, а также результат — вы не можете предположить, что «эффекты неопределенности» будут содержаться в * просто * взаимодействиях с одной переменной. См. Например [this] (https://blogs.msdn.microsoft.com/oldnewthing/20140627-00/?p=633), [это] (http://blog.regehr.org/archives/213) & [это] (http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html). –

Вы должны инициализировать переменную zi_saptamana иметь переключатель работает в вашей программе, чтобы сделать это просто поставить это заявление перед переключателем: —

он будет принимать значение целого числа от пользователя и переключатель будет работать в соответствии к этому.

Область видимости переменных в C++: локальные и глобальные переменные

Всем привет! Сегодня мы затронем тему, которую должны были изучить еще в самом начале пути изучения C++ — область видимости переменных. Мы разберем, что такое локальные и глобальные переменные.

Область видимости переменных в C++

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

В C++ существуют отдельные блоки, которые начинаются с открывающей скобки ( < ) и заканчиваются соответственно закрывающей скобкой ( >). Такими блоками являются циклы (for, while, do while) и функции.

В примере ниже, программист ошибся с областью видимости:

  • Он создал переменную j во втором цикле.
  • Использовав ее в первом цикле for он вынудил компилятор сообщить об ошибке (переменной j больше нет, поскольку второй цикл закончил свою работу).

Глобальные переменные в C++

Глобальными переменными называются те переменные, которые были созданы вне тела какого-то блока. Их можно всегда использовать во всей вашей программе, вплоть до ее окончания работы. В примере ниже мы создали две глобальные переменные global и global_too и использовали их в функции summa :

Локальные переменные

Локальные переменные — это переменные созданные в блоках. Областью видимости таких переменных является блоки ( и все их дочерние ), а также их область видимости не распространяется на другие блоки. Как ни как, но эти переменные созданы в отдельных блоках.

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

Распространенной ошибкой среди начинающих программистов является использование локальных переменных в других блоках. Например ниже мы решили использовать переменную cost в функции summa , хотя мы ее создали в совершенно другой функции — main .

А вот, если мы вызовем функцию sait_message то результатом будет:

Вот так глобальная переменная уступает локальной!

Мы советуем вам не создавать переменные с одинаковыми именами, поскольку в будущем вам будет тяжело разобраться в коде, если там будут присутствовать одинаковые переменные.

Глобальный оператор разрешения

В случае создания двух переменных с одинаковым именем (одна из которых является глобальной, а другая локальной) при использовании в блоке, в котором была объявлена локальная переменная, можно использовать и глобальную переменную. Для ее использования нужно всего лишь применить глобальный оператор разрешения.

Глобальный оператор разрешения — это два подряд поставленные двоеточия, с помощью которых мы говорим компилятору, что хотим использовать глобальную переменную, а не локальную.

Чтобы использовать глобальный оператор разрешения нужно применять данную конструкцию:

Ссылка на основную публикацию
Adblock
detector