Программа работает по-разному в режимах Debug и Release

Этот пост из серии " :sunglasses:Смотрите, я баг нашёл :grin:"
Нашёл в интернет нужный код, но он компилируется только в линуксе (потому что используются старые библиотеки, которые под винду уже не найти).
Выпилил эти библиотеки, заменив их на актуальные аналоги. Теперь проект нормально собирается как в линуксе, так и в вижуалке.
Что я сделал:

  1. Сгрёб все cpp/h-файлы в одну папку (так удобнее между ними переключаться).
  2. Заменил библиотеки freeglut -> GLFW + GLEW, libpng -> stbImage.
  3. Навернул на всё это свою камеру.

Ничего больше не менял. Ну кроме путей к файлам текстур.
Однако, в ходе тестирования обнаружились очень странные вещи. Например, при запуске в линуксе изображение нормальное. А на винде тот же код выдаёт перевёрнутую матрицу. Но это-то ладно. С камерой должно быть всё просто. Я ещё не до конца разобрался, как в том проекте устроена камера.
А вот следующее чюдо вообще не понятно. Есть код:

#include "ConfigTables.h"

void _eatComment(FILE* fp){
	char str[100];
#ifdef _WIN32
	fscanf_s(fp, "\n//");
#else
	fscanf(fp, "\n//");
#endif // _WIN32
	while (str[0] != '\n')
	{
#ifdef _WIN32
		fscanf_s(fp, "%c", str);
#else
		fscanf(fp, "%c", str);
#endif // _WIN32
	}
}

int ConfigTables::Load(const char* path){

#ifdef _WIN32
	FILE* fp;
	if (fopen_s(&fp, path, "r"))
#else
	FILE* fp = fopen(path, "r");
	if (!fp)
#endif // _WIN32
	{
		return false;
	}

	if(fp){
		// eat comment
		_eatComment(fp);

		// load the tri counts
		for(int i = 0; i < 256; i++){	
			int count = 0;
#ifdef _WIN32
			fscanf_s(fp, "%d", &count);
#else
			fscanf(fp, "%d", &count);
#endif // _WIN32
			TriCount[i] = count;
#ifdef CONFIG_TABLES_DEBUG
			printf("%d ", count);
#endif
		}
#ifdef CONFIG_TABLES_DEBUG
		printf("\n\n");
#endif
	
		// eat the next comment
		_eatComment(fp);

		// load the triangle lists
		for(int i = 0; i < 256; i++){
			for(int j = 0; j < 15; j++){
				int ti = 0; // tri index
#ifdef _WIN32
				fscanf_s(fp, "%d", &ti); <<<<<<<<<вот тут в релизе всегда нули
#else
				fscanf(fp, "%d", &ti);
#endif // _WIN32
				TriLists[i][j] = ti;
#ifdef CONFIG_TABLES_DEBUG
				printf("%d ", TriLists[i][j]);
#endif
			}
#ifdef CONFIG_TABLES_DEBUG
			printf("\n");
#endif
		}
	
		fclose(fp);
		return 1;
	}
	
	// error opening file
	return 0;
}

Оно парсит текстовый файл, доставая из него таблицу треугольников marching cubes. Её можно и вручную в массив забить (я потом так и сделаю) и должно заработать. Но данный пост не про это.
Прикол в том, что в дебаге это работает, а в релизе во втором цикле получаются нули. Если внимательно присмотреться, то можно увидеть, что функция _eatComment содержит ошибки. Если переписать вот так:

void _eatComment(FILE* fp)
{
	char c = 0;
#ifdef _WIN32
	fscanf_s(fp, "\n//");
#else
	fscanf(fp, "\n//");
#endif // _WIN32
	while (c != '\n')
	{
#ifdef _WIN32
		fscanf_s(fp, "%c", &c, 1);
#else
		fscanf(fp, "%c", &c);
#endif // _WIN32
	}
}

то таблица правильно считывается как в дебаге, так и в релизе. Но тут начинаются чюдеса. В дебаге матрица остаётся перевёрнутой, а в релизе она переворачивается в нормальное состояние! :dizzy_face: Верх становится верхом, а низ низом.
Проверил код парсинга в пустом проекте - то же самое. Но как оно вообще компилируется, если в функцию передаётся неправильное количество аргументов? И почему не крашится, если вместо ссылки на char передаётся char[100] без ссылки?

str вполне себе ссылка на начало массива.

У этих функций переменное количество параметров. Предположу, что разбор форматной строки происходит уже во время работы программы, тогда и становится понятно, сколько нужно аргументов. Кстати, Visual Studio проводит проверку форматной строки и выдает предупреждение “Warning C4473 ‘scanf_s’ : not enough arguments passed for format string”.

А если включить CONFIG_TABLES_DEBUG, то тоже будет различаться вывод в дебаг и релиз режимах?

Оно и так включено. Сейчас попробовал выключить - всё то же самое. Переворачивается. Разница только в том, что содержимое массива не выводится в консоль.
Еще раз уточню, что проблема не в матрице. Она криво работает, потому что я неправильно управляю камерой. Если бы дело было только в этом, я бы даже пост не создавал.
Проблема именно в том, почему в разных режимах получается разный результат.
Например, сегодня я отрефакторил классы матриц. Математику, естественно, не трогал. Просто разделил код на cpp и h. Он написал какую-то странную ошибку. Я убрал ключевое слово inline у функций, на которые он ругался (еще не гуглил, что значит inline) и всё скомпилировалось. Но в дебаге работает (с перевёрнутой матрицей), а в релизе рендерится просто пустой экран. Возможно, где-то что-то неправильно вычисляется.
НО КАК??? :thinking:

Данных маловато. Каким компилятором с какими флагами собираете? Допустим, на таком входном файле в Visual Studio (с изменением конечных значений циклов на 3 и 4) в обоих режимах вывод одинаковый:

//test
1 2 3
//data
1 2 3 4
5 6 7 8
9 10 11 12

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

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

Там face culling отключен. До рефакторинга матрицы, рендерилось в обоих режимах. Повторный рефакторинг матриц решил проблему. Рендериться стало в обоих режимах (однако, переворот никуда не делся). Я даже не понял, что именно было не так. Я просто вернул всё как было и заново вставил уже отрефакторенный код.
Автор оригинального кода использует старый OpenGL, но, зачем-то, считает матрицы вручную :man_shrugging: Хотя, достаточно было использовать glTranslate().

На винде собираю в вижуалке со стандартными параметрами. Ничего пока не менял. Хотя вот сейчас только вспомнил, что я для Debug и Release прописал одни и те же библиотеки. То есть, в релизе используются дебаг-версии библиотек. Возможно, проблема в этом :point_up: Но тогда глючить должно в релизе, а у меня наоборот :thinking:
А в линуксе использую вот такой MakeFile:

FLAGS = -g -Wall
SRC=./src/*.cpp
OUTPUTFILE=./bin/terrasculpt
LIBS=-lglfw -lGLEW -lX11 -lGL -lGLU -lstdc++
INCLUDE = -I/usr/share/include -I/usr/include -L/usr/local/lib

test:
	g++ -o $(OUTPUTFILE) $(FLAGS) $(INCLUDE) $(SRC) $(LIBS)
clean:
	rm -f ./bin/*.o $(OUTPUTFILE)

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

Разобрался, как в этом проекте генерируются матрицы и полностью выпилил стандартную камеру, заменив её на свою. Теперь работает правильно в Debug и Release. Однако, fov какой-то странный. Стоит, как обычно, 45 градусов, но при развороте камеры заметен эффект рыбьего глаза. Видимо, автор допустил какие-то ошибки при расчёте матрицы. Я пытался заменить на библиотеку GLM, но так рендерится пустой экран :man_shrugging: Видимо, там ещё в шейдерах матрицы как-то по-особому перемножаются :thinking: Но это фигня. Главное что матрица теперь не переворачивается в зависимости от режима сборки. Я, кстати, так и не понял, почему в разных режимах оно по-разному работало :thinking: По-этому, тема не закрыта.

Без проекта целиком (со странным поведением) можно только гадать.

Я выложу проект, когда его до конца отрефакторю.

Но тогда уже негде будет искать причины разного поведения.

я коммичу изменения