Различия между запуском исполняемого файла с помощью отладчика Visual Studio и без отладчика

Я пытаюсь отладить проблему, в которой исполняемый файл производит повторяемый вывод (который я хочу) при выполнении непосредственно из Visual Studio, но не создает повторяемый вывод при выполнении из командной строки. Это однопоточное приложение, поэтому там не должно быть какого-либо странного поведения с точки зрения времени.

Может кто-нибудь подсчитать, какие возможные различия могут быть между двумя средами?

Я уверен, что фактический исполняемый файл тот же - они оба являются сборками релизов и работают с тем же .exe файлом.

Ниже приведены условия и результаты:

  • Запуск непосредственно из командной строки (cmd): Не повторяющийся вывод
  • Запуск из Visual Studio с отладкой (F5): Повторяемый вывод
  • Запуск из Visual Studio без отладки (Ctrl-F5): Не повторяющийся вывод

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

Исходя из этих результатов, похоже, что запуск "с помощью отладки" (даже в сборке Release) каким-то образом устраняет проблему. Означает ли это, что это вероятный преступник? В чем разница между запуском исполняемого файла с помощью отладки и без?

РЕШЕНИЕ: Как было указано в принятом ответе, проблема была отладочной кучей. Проблема заключалась в том, что в глубине нашего кода кто-то обращался к частям большого массива, прежде чем они были инициализированы. Они выделили память с помощью malloc и не инициализировали память до 0. Куча отладки (предположим) заполнила бы массив некоторым повторяемым значением, тогда как отладчик не был присоединен (т.е. При запуске из командной строки или с помощью Ctrl-F5) значения были более случайными и иногда приводили к незначительным отклонениям в поведении программы. К сожалению, настройка была настолько тонкой, что почти незаметна, и соответствующая память была надлежащим образом reset после первого "кадра" обработки, но начальные условия были уже немного разными, и ущерб был нанесен. Теория хаоса в действии! Спасибо за руководство.

Один замечательный отладочный совет, который помог: написать пользовательский malloc, который сразу заполняет память полностью случайными данными. Таким образом, вы можете убедиться, что вы правильно инициализируете его самостоятельно, прежде чем использовать его, иначе ваши результаты будут (надеюсь) безумными каждый раз, когда вы его запускаете - даже в режиме отладки с помощью отладочной кучи!

Ответ 1

Windows Heap ведет себя по-другому, если процесс запускается в отладчике. Чтобы отключить это поведение (чтобы найти проблему при отладке), добавьте _NO_DEBUG_HEAP = 1 для среды (например, этот вопрос).

В качестве альтернативы вы можете подключиться к процессу в начале выполнения программы. Затем куча не войдет в режим отладки. Добавьте строку DebugBreak() где-то в начале выполнения, запустите с помощью Ctrl + F5 и начните отладку при запросе.

Ответ 2

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

Проблема будет появляться, когда я имел дело с числами, которые были немного разными, но численно неотличимыми для машины. Если два удвоения отличаются менее чем на numeric_limits<double>::epsilon(), они считаются одинаковыми для машины. Следовательно, выражения типа:

if (num1==num2)...

или

if (num1<num2)...
...

может привести к ярким эффектам.

Эти яркие эффекты могут отличаться при запуске в режиме отладки или выпуска. Причина в том, что библиотеки времени выполнения отладки/выпуска различаются. Кроме того, и, самое главное, компиляция выполняется с различными оптимизациями кода. Разница между версией командной строки командной строки и версией отладочного окна (F5) также объясняется небольшими различиями в оптимизации.

Если вы используете VS, вы можете посмотреть влияние различных параметров компиляции и оптимизаций в разделе C/C++ и Linker в меню Properties.

Чтобы избежать этой проблемы, я рекомендую использовать средства numeric_limits из библиотеки <limits> STL. Например, реализация оператора с меньшим количеством должна быть примерно такой:

bool operator<(double num1, double num2) {
    double difference=fabs(num1-num2);
    if (difference>numeric_limits<double>::epsilon()) {
        if (num1 < num2) return true;
        return false;
    }
    return false;
}