LINUX.ORG.RU

g++ баг?


0

1

Доброго времени суток. Недавно пробовал написать простой «морской бой» на g++ и вот что получил: Компилятор (все по дефолту) некорректно обрабатывает циклы и не всегда правильно работает с массивами. Я и раньше замечал подобное, но сейчас у меня появилась реальная проблема.

	int Field1[9][9];

	for (int x=0;x<10;x++)
	{
		for (int y=0;y<10;y++)
		{
		Field1[x][y]=0; cout << x << y;}
	}

Dropbox

Программа элементарная. Однако: 1. [6][9],[7][9],[8][9],[9][9] элементы массива заполняются элементами, взятыми «с потолка»; 2.С чего-то вдруг компилятор превратил for в бесконечный цикл, так что программа вообще не завершается сама.

Причем на Dev-C++ под виндой все прекрасно присваивается и выводится( правда, некорректное завершение работы происходит).Обидно, знаете. Надеюсь на вашу помощь.

Правка №1:

Господа, обратите внимание! Массивы начинаются с НУЛЯ, не с единицы. Там 10 элементов. А в цикле если x/y < 10 (10 не меньше 10), то все работает нормально. То есть, значения x и y меняются с 0 до 9. Пожалуйста, проверяйте прогу, прежде чем комментировать. У меня есть повод говорить о баге компилятора, поскольку под окнами все отлично работает.



Последнее исправление: ms-dos32 (всего исправлений: 3)

кто-то не умеет считать кол-во элементов в массиве и/или кол-во итераций в цикле

aho
()

Посмотри внимательно на размеры массива же.

Ну и некорректное завершение работы могло бы насторожить, кстати говоря.

gizzka ★★
()

В твоем массиве 9x9 = 81 элемент (0..8)x(0..8), элементов с девятками в номере быть не может. Ты просто лезешь за границу массива.

unanimous ★★★★★
()
Ответ на: комментарий от unanimous

Ну обьясните мне, почему там (0...8)X(0...8), а не (0...9)Х(0...9)? Если не ошибаюсь, это «ошибка последнего столба».

ms-dos32
() автор топика
Ответ на: комментарий от strangeman

А когда у нас x==9 и выполняется Field1[x][y]=0

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

> И что, оно не сегфолтится? Странно...

Потому что защита памяти на x86 происходит страницами. Для 81 элемента типа int массив занимает жалкую сотню байт в памяти. Какова вероятность того, что последний элемент пересечет границы страницы?

unanimous ★★★★★
()

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

thesame ★★★★
()
Ответ на: комментарий от ms-dos32

> Ну обьясните мне

Потому что int x[9] — это объявление массива с 9 элементами: x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8].

unanimous ★★★★★
()
Ответ на: комментарий от unanimous

Благодарю вас за понимание снисходительность.

ms-dos32
() автор топика
Ответ на: комментарий от delete83

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

ms-dos32
() автор топика
Ответ на: комментарий от ms-dos32

> Это-то я понял, просто сделал скрин для тех, кто не верил мне насчет невозможности работы этого кода под виндой.

А ты думал, он вообще запускаться не будет? Считай, что получил сегфолт виндовый.

cipher ★★★★★
()
Ответ на: комментарий от Eddy_Em

> Интересно, а как это у него в мастдае работало?

Не знаю, что у него там «работало», а судя по скрину ошибки выхода за границу были.

unanimous ★★★★★
()
Ответ на: комментарий от ms-dos32

Меня больше смущает, что ты говоришь, что в Linux этот код не падает в segfault. Должна быть такая же ошибка в рантайме.

delete83 ★★
()
Ответ на: комментарий от unanimous

Дураку понятно, что ошибка выхода за границу массива будет ближе к его концу, потому что «двумерный массив» в C — это просто одномерный, вытянутый по строкам (в Фортране — по столбцам). «Лишние» элементы будут находиться в конце, поэтому прежде чем получить сегфолт программа успеет вывести на экран большую часть содержимого массива.

unanimous ★★★★★
()

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

dave ★★★★★
()
Ответ на: комментарий от ms-dos32

Записывается. На шаге 9 10 и 10 9, при компиляции без оптимизаций велик шанс, что x располагается именно там.

note173 ★★★★★
()
Ответ на: комментарий от delete83

> Меня больше смущает, что ты говоришь, что в Linux этот код не падает в segfault.

Он падает, но не всегда. Я же писал, что память защищается по страницам, которые размером 4096 байт.

Ошибка рантайма в винде — это скорее всего runtime проверка массива, включенная компилятором для DEBUG-версии (а она, кажется такая по умолчанию в VS)

unanimous ★★★★★
()
Ответ на: комментарий от dave

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

ms-dos32
() автор топика
Ответ на: комментарий от ms-dos32

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

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

ananas ★★★★★
()
Ответ на: комментарий от unanimous

Ошибку исправил, все работает корректно. Ошибка заключалась в искривлении мозгов. Всем спасибо.

ms-dos32
() автор топика

>поскольку под окнами все отлично работает.

мдя. Я одного не понимаю, почему сразу гонят на компилятор?

Booster ★★
()
Ответ на: комментарий от unanimous

>Он падает, но не всегда. Я же писал, что память защищается по страницам, которые размером 4096 байт.

Причём здесь страница? Это автоматический массив.

Booster ★★
()
Ответ на: комментарий от unanimous

Это статический массив

Код по ссылке посмотри, прежде чем вызывающе неверную информацию писать.

#include <iostream>
using std::cout;
using std::endl;
int main()
{
	int Field1[10][10];

	for (int x=0;x<10;x++)
	{

	for(int y=0;y<10;y++)
		Field1[x][y]=0;

	}
	cout << "    A B C D E F G H I J\n";
	for (int i=0;i<10;i++)
	{
	cout << i <<": ";

		for(int x=0;x<10;x++)
		
		{int y=0;
		cout <<" "<<Field1[y][x];
		y++;
		}
		cout << endl;
	}

	return 0;
}
geekless ★★
()
Ответ на: комментарий от unanimous

Сдается мне, не все так просто. Сейчас перезагрузился в Linux и проверил кое-что. Пока x не достигнет 9, все работает как надо, однако при x=9 начинаются чудеса. y по бесконечному циклу меняет свое значение от 1 до 5 и потом снова начинает с 1. Сдается мне, при модификации памяти за пределами массива мы залезаем в область, где размещается переменная y, что вообще странно. Ведь эта переменная существует только внутри цикла и память под нее должна выделяться случайно. Или я неправильно думаю?

P.S. Из примерно 15 запусков программа зависла одинаковым образом в 100% случаев.

delete83 ★★
()
Ответ на: комментарий от delete83

Я конечно понимаю, что в программе ошибка, но такое поведение настораживает. Ладно здесь всего десяток строк, а если будет такое поведение в программе из 10 000 строк? Как там искать ошибку? Ведь даже не понятно, какого рода ошибка происходит.

delete83 ★★
()
Ответ на: комментарий от delete83

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

ms-dos32
() автор топика
Ответ на: комментарий от delete83

Простите, чье поведение? Мое или проги? :)

ms-dos32
() автор топика
Ответ на: комментарий от hizel

Проверил на gcc. Те же яйца, только в профиль. Печально. Вот так, наверное, и появляются легенды о плавающих багах, которые не могут поймать годами.

delete83 ★★
()
Ответ на: комментарий от ms-dos32

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

Так что unanimous не прав, когда относительно данного массива пишет:

что память защищается по страницам, которые размером 4096 байт.

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

geekless ★★
()
Ответ на: комментарий от delete83

Это фигня. Вот обращение по адресу нулевой указатель + некоторое довольно большое смещение у меня давало гораздо более веселые и неуловимые эффекты. :)

geekless ★★
()
Ответ на: комментарий от geekless

Для ясности:

s/Сегфолта не будет./Сегфолта в момент buffer overrun от обращения к невыделенной памяти не будет./

Понятно, что позже сегфолт может вылететь запросто.

geekless ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.