Есть ли разница в компиляции / выполнении кода в разных операционных системах? - PullRequest
0 голосов
/ 06 февраля 2019

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

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

Я использую 2 компьютера.На моем рабочем месте работает Windows XP SP3.В этом, программа работала нормально.

В моем доме работает Windows 7 SP1.Он скомпилировал код, но программа не сработала.

Я пишу и компилирую, используя DEV C ++ и TDM GCC 5.1.0 в обеих системах.

#include<iostream>
using namespace std;

int main (void) {
  int* pointer;
  cout << "pointer == "  <<  pointer << "\n";
  cout << "*pointer == " << *pointer << "\n"; // this is the line where the program stops. 
  cout << "&pointer == " << &pointer << "\n";

return 0;}

Вывод на первом компьютере был примерно таким:

pointer == 0x000001234
*pointer == some garbage value
&pointer == 0x000007865

На втором компьютере он останавливается на второй строке.

pointer == 0x1

Я понимаю, что указатель не был присвоен переменной.Таким образом, он не хранит правильный адрес.Тем не менее, он должен по крайней мере показать значение мусора внутри него, или «0», чтобы указать, что у него еще нет адреса, на который можно указать.Я знаю, что код правильный, потому что он отлично работал на первом ПК.Но я не понимаю, почему это не удалось на другом компьютере.

Ответы [ 2 ]

0 голосов
/ 06 февраля 2019

Я понимаю, что указатель не был назначен переменной.Таким образом, он не хранит правильный адрес.Тем не менее, он должен, по крайней мере, показать значение мусора внутри него или «0», чтобы указать, что у него еще нет адреса, на который можно указать.

Это так!Это был 0x000001234.

К сожалению, вы тогда попытались разыменовать этот недействительный указатель и вывести значение int, которое не существует.Вы не можете этого сделать.

Если бы вы этого не сделали, мы бы дошли до третьей строки, где 0x000007865 будет правильно представлять адрес указателя, который является объектом с именемpointer и введите int*, который действительно существует.

Я знаю, что код правильный, потому что он отлично работал на первом ПК.

Одна из вещейс C ++ вам придется привыкнуть к тому, что «похоже, что он работает на одном компьютере» - это очень далеко от доказательства правильности кода.Прочитайте о неопределенное поведение и плачьте медленными слезами.

Но я не понимаю, почему это не удалось на другом компьютере.

Потому что код не верно, и вам не повезло на этот раз.

Мы могли бы проанализировать несколько причин, почему это работает на одной системе, а не на другой, и там это причин для этого.Но уже поздно, и вы только начинаете, и поскольку это неопределенное поведение , это не имеет значения .:)

0 голосов
/ 06 февраля 2019

Я знаю, что код правильный, потому что он отлично работал на первом ПК

Вы не знаете ничего подобного.

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

Поведение - undefined , а не «определен для определенного согласованного наблюдаемого режима сбоя».

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

Даже в этом случаепо крайней мере, показать значение мусора внутри него

Это сделал.Но затем вы попросили разыменовать это мусорное значение.

Чтение любой переменной с неопределенным значением само по себе является неопределенным поведением, поэтому первая часть UB читает значение указателя.

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

Если вы успешно загрузили какое-то целое число с этого адреса, это третья часть неопределенного поведения, потому что снова его значение не определено.

Итак,Непосредственные наихудшие ловушки (со значениями аппаратного перехвата и ограничительным выравниванием):

  1. прочитайте неуказанное значение указателя, получите представление прерывания, умрите с аппаратным прерыванием
  2. ИЛИ прочитайтенеопределенное значение указателя, интерпретировать его как неверно выровненный адрес, умереть с ошибкой шины
  3. ИЛИ следовать за неопределенным указателем на не назначенный адрес, умереть с нарушением сегмента
  4. ИЛИ пережить все предыдущиешаги - по чистой случайности - загрузить случайное значение из некоторого места в памяти.Затем умрите, потому что это значение представляет собой ловушку.

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

...