Страница 7 из 9

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

Добавлено: 09 дек 2020, 18:27
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:

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

Добавлено: 09 дек 2020, 18:34
Kost_irk
Похоже скобок не хватает, условия if then else без скобок следует использовать очнеь аккуратно.

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

Добавлено: 09 дек 2020, 18:43
Duhas
специально убрано для читаемости, нет никаких проблем при наличии только одного действия. скобки ничего не меняют, на всякий случай было попробовано.

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

Добавлено: 09 дек 2020, 20:14
alex_sar
насколько я понял из описаний ошибок, генерируется код с обращениями к адресам слишком "далёким" в адресном пространстве, в результате получаются вот такие странности. там написано какие опции gcc указать чтобы он не тупил.

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

Добавлено: 09 дек 2020, 21:02
Duhas
да как бы нет слишком далеких адресов, ветвления с относительными переходами могли начудить, удивляет что такое бывает )

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

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

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

	for(N=3;N>0;N--)        //N=3 т.к.
	{
		Ts=X/pow(10,N-1)-T;
		T=(Ts+T)*10;
                 ......

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

Добавлено: 09 дек 2020, 21:25
Duhas
ну во-первых - я ж писал, не ко мне вопросы )
во-вторых - для интерфейсных задач с обновлениями в десятки герц - вообще пофиг.

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

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

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

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

Добавлено: 09 дек 2020, 23:22
kochevnik
Да последний пакет с состоянием аборт хз почему, нет времени копать. Большинство файлов без проблем

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

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

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

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

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

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

P.S. Нужно понимать, что язык C/C++ это по сути макроассемблер, т.е. при выполнении программы автоматически не прозводится никакого контроля данных, размерностей переменных, корректности адресов перехода и т.п. Т.е. что написали, то и получите. :)

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

Добавлено: 10 дек 2020, 07:46
MX_Master
Когда у меня в коде появляются чудеса, я первым делом лезу отключать оптимизацию. И вуаля, всё сразу работает как задумано. После этого, в нужных местах расставляю всякие volatile..

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

Добавлено: 13 мар 2021, 13:34
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
:))

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

Добавлено: 13 мар 2021, 14:52
MX_Master
uralpt писал(а): Стояла задача в битовом представлении слить 2 значения char в строку как X + Y = XY...
Ещё б понять нафига это нужно :hehehe:

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

Добавлено: 13 мар 2021, 15:21
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]);

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

Добавлено: 13 мар 2021, 16:33
Serg
:yawn:
Serg писал(а): Нужно понимать, что язык C/C++ это по сути макроассемблер, т.е. при выполнении программы автоматически не прозводится никакого контроля данных, размерностей переменных, корректности адресов перехода и т.п. Т.е. что написали, то и получите.

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

Добавлено: 13 мар 2021, 17:22
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' в нашем примере) получается явно не сумма этих двух значений?

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

Добавлено: 13 мар 2021, 17:41
uralpt
Serg писал(а): по сути макроассемблер
неа, это тут ни при чем.
Нашел ответ (за 10 минут, умение правильно формулировать вопросы гуглю явно не мое, поэтому - вчерашний вечер потрачен под эгидой борьбы с глюками :)) -
Если первый бит в char = 0, то он рассматривается как символ ASCII. Если первый бит = 1, то он рассматривается как часть многобайтового символа (UTF8 к примеру). И тогда первый байт содержит количество байт символа, закодированное в единичной(!) системе счисления. А за ним следует "0" — бит терминатор, означающий завершение кода размера.
Интересные чюдеса однако:))

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

Добавлено: 13 мар 2021, 18:45
Сергей Саныч
Объявите переменную как unsigned char и всё пройдет (или uint8_t).
char, как правило, знаковый тип. 10000000 - это минус 128, естественно, расширяется в равное отрицательное значение. А UTF тут вообще ни при чем.

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

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