Программистские задачки и хитрости

Duhas
Мастер
Сообщения: 1949
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 284
Настоящее имя: Андрей
Откуда: Красноярск
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Duhas »

На самом деле проблемы то как таковой нет в данный момент, итоговый код компилится и работает, однако, хотелось бы понимать что это было :thinking:

Ок, попробуем по подробнее.

есть вот такой код, и он падает при сборке в приведенную выше ошибку

Код: Выделить всё

void HD44780::SendNumber(int8_t x ) //вывод в 10-ной системе
{
	uint8_t X;
	if(x<0)
	{
		Send_Data(0b00101101);// отправляем "-"
		X=-x;              //делаем число положительным
	}
	else
	{
		X=x;
	}
	uint8_t Ts,T=0,N;
	for(N=3;N>0;N--)        //N=3 т.к.
	{
		Ts=X/pow(10,N-1)-T;
		T=(Ts+T)*10;

		if (Ts)
			Send_Data(Ts+0x30);
		else
			if (_leadingZeroes)
				Send_Data(' ');
	}
}	
А вот такой - уже не падает

Код: Выделить всё

void HD44780::SendNumber(int8_t x ) //вывод в 10-ной системе
{
	uint8_t X;
	if(x<0)
	{
		Send_Data(0b00101101);// отправляем "-"
		X=-x;              //делаем число положительным
	}
	else
	{
		X=x;
	}
	uint8_t Ts,T=0,N;
	for(N=3;N>0;N--)        //N=3 т.к.
	{
		Ts=X/pow(10,N-1)-T;
		T=(Ts+T)*10;

		if (Ts)
			Send_Data(Ts+0x30);
		else
			if (_leadingZeroes)
				Send_Data(' ');
			else
				Send_Data(Ts+0x30);
	}
}
на самом деле код в итоге выглядит не совсем так и все корректно работает, но хотелось бы понять - какого лешего?
самое интересное, что замена переменной _leadingZeroes на некоторую локальную производную от Ts, например, приводит к нормальной компиляции..

вариант с трудностями компилятора в реализации ветвлений на относительных переходах интересный, но выглядит печально )

ПС я не шибко програмер, я таки больше по железкам.
ППС этот код студенты писали, я там мелочи всякие допиливал :monkey: так что за качество и стиль - не пинать :wik:
Kost_irk
Мастер
Сообщения: 995
Зарегистрирован: 19 июл 2018, 07:46
Репутация: 193
Откуда: Иркутск
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Kost_irk »

Похоже скобок не хватает, условия if then else без скобок следует использовать очнеь аккуратно.
Duhas
Мастер
Сообщения: 1949
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 284
Настоящее имя: Андрей
Откуда: Красноярск
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Duhas »

специально убрано для читаемости, нет никаких проблем при наличии только одного действия. скобки ничего не меняют, на всякий случай было попробовано.
alex_sar
Мастер
Сообщения: 1630
Зарегистрирован: 28 авг 2018, 17:13
Репутация: 272
Настоящее имя: Алексей
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение alex_sar »

насколько я понял из описаний ошибок, генерируется код с обращениями к адресам слишком "далёким" в адресном пространстве, в результате получаются вот такие странности. там написано какие опции gcc указать чтобы он не тупил.
Duhas
Мастер
Сообщения: 1949
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 284
Настоящее имя: Андрей
Откуда: Красноярск
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Duhas »

да как бы нет слишком далеких адресов, ветвления с относительными переходами могли начудить, удивляет что такое бывает )
alex_sar
Мастер
Сообщения: 1630
Зарегистрирован: 28 авг 2018, 17:13
Репутация: 272
Настоящее имя: Алексей
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение alex_sar »

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

Код: Выделить всё

	for(N=3;N>0;N--)        //N=3 т.к.
	{
		Ts=X/pow(10,N-1)-T;
		T=(Ts+T)*10;
                 ......
Duhas
Мастер
Сообщения: 1949
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 284
Настоящее имя: Андрей
Откуда: Красноярск
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Duhas »

ну во-первых - я ж писал, не ко мне вопросы )
во-вторых - для интерфейсных задач с обновлениями в десятки герц - вообще пофиг.
Аватара пользователя
Serg
Мастер
Сообщения: 21923
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5181
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

alex_sar писал(а): а это кармическое наказание за вот такой вот код в микроконтроллере
нормальный код, хоть и не оптимальный.
Duhas писал(а): да как бы нет слишком далеких адресов, ветвления с относительными переходами могли начудить, удивляет что такое бывает )
Надо смотреть какой ассемблерный код получается в обоих случаях (с ошибкой и без), выявлять разницу и изучать.
Ассемблерный код получается командой "gcc -S file.c" - в результате появится file.s.

P.S. И в подобных "непонятках" первым делом надо пробовать отключать оптимизацию.
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
kochevnik
Мастер
Сообщения: 224
Зарегистрирован: 13 окт 2013, 16:24
Репутация: 9
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение kochevnik »

Да последний пакет с состоянием аборт хз почему, нет времени копать. Большинство файлов без проблем
Duhas
Мастер
Сообщения: 1949
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 284
Настоящее имя: Андрей
Откуда: Красноярск
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Duhas »

Serg писал(а): 09 дек 2020, 21:35 Надо смотреть какой ассемблерный код получается в обоих случаях (с ошибкой и без), выявлять разницу и изучать.
Ассемблерный код получается командой "gcc -S file.c" - в результате появится file.s.

P.S. И в подобных "непонятках" первым делом надо пробовать отключать оптимизацию.
если интересно - можно и копнуть.

вроде как уважаемые люди не советовали отключать оптимизацию на МК.. хз правда ли, давно в голове сидит.
Аватара пользователя
Serg
Мастер
Сообщения: 21923
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5181
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

При отладке любую оптимизацию всегда нужно отключать (-O0), иначе например пошаговое выполнение программы может быть весьма чудесатым. :)
Если отлаженная программа нормально помещается в память (без отладочной информации) и работает с приемлемой скоростью, то оптимизацию включать не стоит совсем. Хорошо написанный код практически не оптимизируется. :)
Если же оптимизация нужна, то скомпилировав программу с опциями оптимизации нужно как минимум снова "прогнать" весь комплект тестов. А в идеале при написании кода нужно чётко понимать (читайте доки - они rulez! :)) как именно компилятор будет его оптимизировать.

P.S. Нужно понимать, что язык C/C++ это по сути макроассемблер, т.е. при выполнении программы автоматически не прозводится никакого контроля данных, размерностей переменных, корректности адресов перехода и т.п. Т.е. что написали, то и получите. :)
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Аватара пользователя
MX_Master
Мастер
Сообщения: 7460
Зарегистрирован: 27 июн 2015, 19:45
Репутация: 3086
Настоящее имя: Михаил
Откуда: Алматы
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение MX_Master »

Когда у меня в коде появляются чудеса, я первым делом лезу отключать оптимизацию. И вуаля, всё сразу работает как задумано. После этого, в нужных местах расставляю всякие volatile..
Аватара пользователя
uralpt
Мастер
Сообщения: 651
Зарегистрирован: 23 ноя 2015, 14:31
Репутация: 104
Настоящее имя: евгений
Откуда: Миасс
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение uralpt »

Стояла задача в битовом представлении слить 2 значения char в строку как X + Y = XY...
С++, VS 2019

Код: Выделить всё

// нужно в битовом виде слить 2 значения char в строку как X + Y = XY

#include <iostream>
#include <bitset>

char mess[2];
unsigned long w;


int main()
{
    mess[0] = 0b01100100;  //если компилятор заругается, можно написать 'd'
    mess[1] = 0b10000000;  //можем написать 'Ђ';

    std::cout << std::bitset<8>(mess[0]) << std::bitset<8>(mess[1]) << "\n"; //выводим наши первичные значения 

    w = mess[0] *256 + mess[1];
    std::cout << std::bitset<16>(w);  //и сверяем со слитой строкой
}

//можно развить темы битового умножения, деления и т.п. :))
результат - строки отличаются как
0110010010000000 и
0110001110000000
:))
Аватара пользователя
MX_Master
Мастер
Сообщения: 7460
Зарегистрирован: 27 июн 2015, 19:45
Репутация: 3086
Настоящее имя: Михаил
Откуда: Алматы
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение MX_Master »

uralpt писал(а): Стояла задача в битовом представлении слить 2 значения char в строку как X + Y = XY...
Ещё б понять нафига это нужно :hehehe:
Аватара пользователя
uralpt
Мастер
Сообщения: 651
Зарегистрирован: 23 ноя 2015, 14:31
Репутация: 104
Настоящее имя: евгений
Откуда: Миасс
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение uralpt »

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

Все чюдеса начинаются из-за этого:

Код: Выделить всё

std::cout << std::bitset<8>(mess[1]) <<"\n";
std::cout << std::bitset<16>(mess[1]) <<"\n";
std::cout << std::bitset<32>(mess[1]);
Аватара пользователя
Serg
Мастер
Сообщения: 21923
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5181
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

:yawn:
Serg писал(а): Нужно понимать, что язык C/C++ это по сути макроассемблер, т.е. при выполнении программы автоматически не прозводится никакого контроля данных, размерностей переменных, корректности адресов перехода и т.п. Т.е. что написали, то и получите.
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Аватара пользователя
uralpt
Мастер
Сообщения: 651
Зарегистрирован: 23 ноя 2015, 14:31
Репутация: 104
Настоящее имя: евгений
Откуда: Миасс
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение uralpt »

Глюк этот победил, а причины его появления до сих пор не понимаю... не гуру я в кодинге.
Может, кто пояснит, а?

Копаю так:
Тип char всегда занимает 8 бит. При представлении в битовом формате символа 'Ђ' имеем 1000 0000. (128 в dec).
Значение, бОльшее чем 8 бит, исходя из принципа big-endian, должно дописываться нолями в начале (пример - 000...000 1000 0000). Это правило работает со всеми символами ASCII вплоть до 0111 1111 (127 dec).
Так почему при попытке представить значение >127(dec) в виде битового значения с размерностью более 8 разрядов я получаю все верхние разряды, заполненные единицами? (почему потом перестает работать правило big-endian?)
Но и на этом странности не заканчиваются. Почему при сложении 1111 1111 1000 0000 со значением, к примеру, 0000 0000 0110 0100 ('d' в нашем примере) получается явно не сумма этих двух значений?
Аватара пользователя
uralpt
Мастер
Сообщения: 651
Зарегистрирован: 23 ноя 2015, 14:31
Репутация: 104
Настоящее имя: евгений
Откуда: Миасс
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение uralpt »

Serg писал(а): по сути макроассемблер
неа, это тут ни при чем.
Нашел ответ (за 10 минут, умение правильно формулировать вопросы гуглю явно не мое, поэтому - вчерашний вечер потрачен под эгидой борьбы с глюками :)) -
Если первый бит в char = 0, то он рассматривается как символ ASCII. Если первый бит = 1, то он рассматривается как часть многобайтового символа (UTF8 к примеру). И тогда первый байт содержит количество байт символа, закодированное в единичной(!) системе счисления. А за ним следует "0" — бит терминатор, означающий завершение кода размера.
Интересные чюдеса однако:))
Аватара пользователя
Сергей Саныч
Мастер
Сообщения: 9116
Зарегистрирован: 30 май 2012, 14:20
Репутация: 2857
Откуда: Тюмень
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Сергей Саныч »

Объявите переменную как unsigned char и всё пройдет (или uint8_t).
char, как правило, знаковый тип. 10000000 - это минус 128, естественно, расширяется в равное отрицательное значение. А UTF тут вообще ни при чем.
Чудес не бывает. Бывают фокусы.
Аватара пользователя
uralpt
Мастер
Сообщения: 651
Зарегистрирован: 23 ноя 2015, 14:31
Репутация: 104
Настоящее имя: евгений
Откуда: Миасс
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение uralpt »

Сергей Саныч, помогло.
И я даже понял, о чем говорил Сергей. Скажу честно - не сразу :))
Компилятор ведь все равно все типы приводит к int.
Пошел читать про преобразования типов и править код :oops:
Ответить

Вернуться в «Оффтоп»