Значение элемента массива вне границ - должен ли он меняться при каждом выполнении или оставаться неизменным? - PullRequest
1 голос
/ 05 июля 2011

Для фактического вопроса перейдите к вопрос часть. Для интересного реального примера неопределенного поведения продолжайте читать:)

Было это перечисление:

struct EnumStruct 
{
   enum Enum
   {
       val0 = 0,
       val1,
       val2,
       val3,
       val4
   };
};

и в некоторой функции у нас было это:

const int arrayCount = 6;
int arr[] = {
        EnumStruct::val0,
        EnumStruct::val1,
        EnumStruct::val2,
        EnumStruct::val3,
        EnumStruct::val4
        InvalidValue
      };    

Затем был цикл, который помещал arrayCount элементы arr в файл. Это была процедура Prepare() для модульных тестов. И модульный тест должен был проверить наличие InvalidValue в файле. Мне был назначен дефект о том, что модульный тест не пройден. Это отлично работает на моей машине, хотя. После нескольких часов отладки я заметил, что InvalidValue на самом деле #define d как -1, и после val4 пропущена запятая. Вы можете только представить ругательства, которые вышли из моих уст в адрес того, кто написал этот код (на самом деле он работал более 3 лет).

Теперь, как вы можете видеть, массив фактически состоит из 5 значений - 0, 1, 2, 3, 3, но цикл также записывает в файл 6-й элемент, что, конечно, является неопределенным поведением. Теперь, хотя технически он является неопределенным, в Windows с MSVC сбоев не происходит - он просто записывает мусор, который находится в этом месте памяти. Дело в том, что если мусор окажется не таким, как 0, 1, 2, 3, or 4, модульные тесты пройдут успешно.

Вопрос : Похоже, что файл .vcproj UT каким-то образом исправлен до его создания. Я не знаю, как они это делают, но с их элементами массива build-of-of-bound всегда равны 0. Мне кажется, что вся виртуальная память установлена ​​в 0 перед выполнением программы. Что это за настройка проекта? Или я воображаю вещи? Я имею в виду, что если бы это была просто удача, что массив находился за пределами 0, то при многократном выполнении моя удача потерпела бы неудачу, не так ли? Но это всегда 0 ... Я в замешательстве. Кстати, когда я строю один и тот же проект, элемент «вне границ» всегда имеет разные значения при каждом выполнении. Можете ли вы объяснить это? Спасибо.

Ответы [ 2 ]

0 голосов
/ 05 июля 2011

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

Есть также некоторые флаги компилятора, которые могут повлиять на это. Чтобы обнаружить неинициализированные проблемы с памятью, иногда отладочные сборки записывают шаблоны в память после выделения из ОС и перед обработкой ее в программе, и другой шаблон после освобождения памяти в программе перед перераспределением (для обнаружения доступа к освобожденной памяти), поэтому что проще определить, что произошло (если вы видите в отладчике, что значение равно 0xDEADBEEF, вы будете знать, что память уже была освобождена программой. Вам нужно будет прочитать документацию компилятора / IDE для более точного информация.

0 голосов
/ 05 июля 2011

Как вы говорите, он не определен, поэтому разработчик может делать все, что угодно.Я вообще не могу говорить о Visual C ++, но я знаю о других продуктах, которые делают такие вещи, как обнуление памяти при запуске отладочных сборок, так что такие вещи, как недопустимые разыменования указателей, потерпят неудачу на месте ошибки.Возможно, что Microsoft делает что-то подобное, я думаю.

...