Вопросы по С/С++ (СИ)

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Аватара пользователя
Мikа
Потрогал лапой паяльник
Сообщения: 343
Зарегистрирован: Пн апр 01, 2013 15:13:40
Откуда: Москва

Re: Вопросы по С/С++ (СИ)

Сообщение Мikа »

Ахахаха!!! Вот ОНО: хрен знает что :D

В общем, такая порграмма:

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

unsigned long int t = 1000000000; (миллиард)


if (t == 1000000000)(миллиард)
{
Опрашивать кнопку t++;

Опрашивать кнопку t--;

Выводить на дисплей  00 00
}
ИтаК, оптимизация отключена. 20 строчек на Си занимают 11 кб. Всё круто.

Включаем: индикатор горит. Видимо, условие t == 1000000000 выполняется. Но если нажать на любую кнопку, будет или t-- или t++. (СТРОГО 1 РАЗ, БЕЗ ДРЕБЕЗГА!). Индикатор гаснет. То есть t != 1000000000. По идее, если нажать противоположную кнопку, число должно вернуться обратно, к значению 1000000000 и индикатор включаться. Только этого не происходит.

Вывод:
unsigned long int t = 1000000000; представляется как хрен знает что, которое будет равно 1000000000(в условии) такому же хрен знает чему.

Однако, если увеличить это хрен знает что на 1 (или уменьшить) происходит потеря битов этого хрен знает чего и обратная операция уже не возвращает исходное число.
Почему я здесь и задаю тупые вопросы?
Потому что хочу научиться.
Реклама
Аватара пользователя
ploop
Модератор
Сообщения: 13490
Зарегистрирован: Ср ноя 26, 2008 16:34:25
Откуда: Тамбовская обл.

Re: Вопросы по С/С++ (СИ)

Сообщение ploop »

По идее, если нажать противоположную кнопку, число должно вернуться обратно
А на практике проскочит значение. Поставьте > или <, вместо == и !=
Реклама
Аватара пользователя
Мikа
Потрогал лапой паяльник
Сообщения: 343
Зарегистрирован: Пн апр 01, 2013 15:13:40
Откуда: Москва

Re: Вопросы по С/С++ (СИ)

Сообщение Мikа »

Я налажал. Я опрашивал кнопки в это же if. Когда вынес опрос кнопок за него, индикатор включается.
Почему я здесь и задаю тупые вопросы?
Потому что хочу научиться.
Аватара пользователя
Kavka
Мудрый кот
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Re: Вопросы по С/С++ (СИ)

Сообщение Kavka »

А если вот так
if (t == 1000000000UL)
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
Мikа
Потрогал лапой паяльник
Сообщения: 343
Зарегистрирован: Пн апр 01, 2013 15:13:40
Откуда: Москва

Re: Вопросы по С/С++ (СИ)

Сообщение Мikа »

Kavka, вы, видимо, мельком прочитали мой последний пост. Я не туда вставил опрос кнопок. Когда поправил - это число возвращается к предыдущему виду. Кстати, а что такое UL? Сегодня на AVR Freaks что-то подобное видел...

А насчёт моего пример, я щас вот что подумал:

Начинается кракозябничество на индикаторе.
Индиктаор работает так:
В порт выводится число, которое лежит в массиве.
Имеется переменная, в которую помещается число, котрое является порядковым номером для того числа, которое мы берём из массива.
В массиве только цифры 0-9.
Если на дисплее видны кракозябры, значит дело в этой самой переменной, в которой лежит номер строки (или ячейки?) массива, котороую надо вывести.
Эта переменная получает своё значение исходя из того, что насчитала функция получения ЧЧ:ММ:СС из секунд. Что-то тут не то, щас вот чай допью и буду "анализировать" :)
Почему я здесь и задаю тупые вопросы?
Потому что хочу научиться.
Реклама
Аватара пользователя
ploop
Модератор
Сообщения: 13490
Зарегистрирован: Ср ноя 26, 2008 16:34:25
Откуда: Тамбовская обл.

Re: Вопросы по С/С++ (СИ)

Сообщение ploop »

Мikа писал(а):Что-то тут не то
Тут просто выход за пределы массива. Поставьте условие перед обращением к массиву - если число больше 9, чтобы зажегся светодиод (есть, надеюсь?). Уверен - загорится.
щас вот чай допью и буду "анализировать" :)
Вот тут фатальная ошибка. Во время написания кода пьют исключительно кофе! При чём крепкий. :)
Реклама
Аватара пользователя
Мikа
Потрогал лапой паяльник
Сообщения: 343
Зарегистрирован: Пн апр 01, 2013 15:13:40
Откуда: Москва

Re: Вопросы по С/С++ (СИ)

Сообщение Мikа »

ploop, то, что он выходит за пределы массива - это очевидно :) Надо найти место, где он это делает и почему. Но путём многократного включения я заметил, что всегда на одном и том же месте начинаются кракозябры. Место как раз рядом с концом положительной части 16битного числа со знаком :) Кофе... Блин, я вообще не пью кофе :))
Почему я здесь и задаю тупые вопросы?
Потому что хочу научиться.
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: Вопросы по С/С++ (СИ)

Сообщение oleg110592 »

Мikа писал(а): Кстати, а что такое UL?
2.3 Константы
Целая константа, например 1234, имеет тип int. Константа типа long завершается буквой l или L, например 123456789L: слишком большое целое, которое невозможно представить как int, будет представлено как long. Беззнаковые константы заканчиваются буквой u или U, а окончание ul или UL говорит о том, что тип константы - unsigned long.

Константы с плавающей точкой имеют десятичную точку (123.4), или экспоненциальную часть (1е-2), или же и то и другое. Если у них нет окончания, считается, что они принадлежат к типу double. Окончание f или F указывает на тип float, а l или L - на тип long double.

Целое значение помимо десятичного может иметь восьмеричное или шестнадцатеричное представление. Если константа начинается с нуля, то она представлена в восьмеричном виде, если с 0x или с 0X, то - в шестнадцатеричном. Например, десятичное целое 31 можно записать как 037 или как 0X1F. Записи восьмеричной и шестнадцатеричной констант могут завершаться буквой L (для указания на тип long) и U (если нужно показать, что константа беззнаковая). Например, константа 0XFUL имеет значение 15 и тип unsigned long.

K&R.
Аватара пользователя
Мikа
Потрогал лапой паяльник
Сообщения: 343
Зарегистрирован: Пн апр 01, 2013 15:13:40
Откуда: Москва

Re: Вопросы по С/С++ (СИ)

Сообщение Мikа »

Спасибо, буду знать :)
Эксперименты продолжаются. Нормально считает до 09:59:59. Если в секундах, то до 35 999. Если сделать t++, получу 10:68:16 Оо

UPD:

Получается такая тема:

09:59:59 - 35 999 (сек)
Делаем t++;, получаем:
10:68:16 - 36 000 (должно быть по идее), но если расчитать по секундам, то 40 096
11:08:16 - это 40 096(сек)

Далее, разница между 10:00:00 и 11:08:16 - это 01:08:16, что (3600 + (08*60=480) + 16) = 4096. Очень похоже на 40096.

Это 36000 + 4096.

А 4096\2 = 2048\2 = 1024. Тоже какое-то не простое число, а 12я степень двойки :) (2:12=4096)

К сообщению прикрепил excel, который переводит число в ЧЧ:ММ:СС, вдруг кто-то решит помочь :)

Прям задачка по математике :facepalm:
Вложения
Расчёт времени.7z
(8.75 КБ) 170 скачиваний
Почему я здесь и задаю тупые вопросы?
Потому что хочу научиться.
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: Вопросы по С/С++ (СИ)

Сообщение oleg110592 »

Проверил на C++ Builder:

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

unsigned long t;
unsigned char h, m, s;

int main(int argc, char* argv[])
{
	t = 80999UL;
	h=(unsigned char)(t / 3600U );//Вычисление часов
	m=(unsigned char)((t - ((unsigned long)h * 3600U )) / 60);//Вычисление минут
	s=(unsigned char)((t - ((unsigned long)h * 3600U ))-((unsigned long)m * 60));//Вычисление секунд
	printf("h = %d", h);
	printf(" \n");
	printf("m = %d", m);
	printf(" \n");
	printf("s = %d", s);
	printf(" \n");
	return 0;
}
результат:
h = 22
m = 29
s = 59

в экселе:
Дано 80 999,00
Часы 22,00
Минуты 29,00
Секунды 59,00
Аватара пользователя
Kavka
Мудрый кот
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Re: Вопросы по С/С++ (СИ)

Сообщение Kavka »

А не используются ли переменные ещё где-нибудь? В других местах кода? Прерывания?

oleg, оно на ПиСишном gcc и так работает.

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

#include <stdio.h>
#include <stdint.h>


void main() {

char h,m,s;
long t;

t=32760;

   h=(t/3600);//Вычисление часов
   m=((t-(h*3600))/60);//Вычисление минут
   s=((t-(h*3600))-(m*60));//Вычисление секунд

printf("%d %d %d\n",h,m,s);


t=75760;

   h=(t/3600);//Вычисление часов
   m=((t-(h*3600))/60);//Вычисление минут
   s=((t-(h*3600))-(m*60));//Вычисление секунд

printf("%d %d %d\n",h,m,s);
}
Вывод:
9 6 0
21 2 40
Последний раз редактировалось Kavka Пн фев 17, 2014 19:49:02, всего редактировалось 2 раза.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение WiseLord »

Слишком много лишних приведений типов и вычислений. Для МК, например, не самый лучший вариант.
Проще - как-то так:

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

#include <stdio.h>

unsigned long t;
unsigned char h, m, s;

int main(int argc, char* argv[])
{
  t = 80999UL;
  s = t % 60;
  t /= 60;
  m = t % 60;
  t /= 60;
  h = t % 24;
  printf("h = %d\nm = %d\ns = %d\n", h, m, s);
  return 0;
}
t при вычислениях разрушается, если это критично - можно временную переменную завести. Хотя обычно такие вычисления делаются в отдельной функции, так что это некритично.
Аватара пользователя
Мikа
Потрогал лапой паяльник
Сообщения: 343
Зарегистрирован: Пн апр 01, 2013 15:13:40
Откуда: Москва

Re: Вопросы по С/С++ (СИ)

Сообщение Мikа »

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

P.S. По поводу кривости кода - я только учусь, щас я в стадии набора опыта и нарабатывании собственной базы знаний. Поэтому если вы где-то видите какие-нибудь ужасные вещи, говорите об этом, это очень поможет. Ещё раз спасибо!
Почему я здесь и задаю тупые вопросы?
Потому что хочу научиться.
Аватара пользователя
Kavka
Мудрый кот
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Re: Вопросы по С/С++ (СИ)

Сообщение Kavka »

WiseLord, у вас 5 делений с 4х байтовым целым, фактически.
Тогда уж вот так.

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

#include <stdio.h>

unsigned long t;
unsigned int  t2;
unsigned char h, m, s;

int main(int argc, char* argv[])
{
  t = 80999UL;

  h = t / 3600U;
  t2 = t % 3600U;
  m = t2 / 60U;
  s = t2 % 60U;

  printf("h = %d\nm = %d\ns = %d\n", h, m, s);
}
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Аватара пользователя
Мikа
Потрогал лапой паяльник
Сообщения: 343
Зарегистрирован: Пн апр 01, 2013 15:13:40
Откуда: Москва

Re: Вопросы по С/С++ (СИ)

Сообщение Мikа »

Парни, алгоритм по вычислению времени работает, может он не самым красивым кодом написан, но он работает. Кстати, некий Александр Писанец (у него куча крутых уроков по СИ AVR на youtube) советует использовать простые операции, типа сложение или вычитание, вместо получения остатка от деления и т.п.

Вопрос, почему всё сходит с ума на пороге 09:59:59.

Кстати, ещё я сегодня кое что попробовал.
Я вставил это:

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

if (h == 10)
{
m=1;
s=1;
}
После вычисления h m s из t, но перед функцией, которая раскидывает h, m, s на hh, hl, mh, ml, sh, sl, которые в последствии выводятся на индикатор.
В результате получилось на дисплее 10:01:01.

Главный вопрос, что там сходит в МК с ума.

Да, отвечая на вышезаданый вопрос о переменных: нет, в процессе пересчёта h m s и всех остальных переменных они больше нигде не используются в принципе. Это функция, у которой нет возможности перейти в другое место при каких-то условиях. Обработчик прерывания тоже с этими числами ничего не делает.

Завтра попробую его выключить в принципе и в ручную поприбавлять значения после 10:01:01. И ещё попробую так, на всякий, заменить свою функцию вычисления h, m, s на те, которые показали вы. Вдруг дело в этом Оо

Ещё раз повторюсь, вопрос не в красоте кода, а в том, почему он начинает выдавать какую-то хренотень при переходе с 09:59:59.
Почему я здесь и задаю тупые вопросы?
Потому что хочу научиться.
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: Вопросы по С/С++ (СИ)

Сообщение oleg110592 »

Мikа писал(а):Александр Писанец советует использовать простые операции, типа сложение или вычитание, вместо получения остатка от деления и т.п.
не всегда, например у stm8 микроконтроллеров есть аппаратно операции деления 16-бит на 16-бит и 16-бит на 8-бит и быстрого знакового умножения 8-бит на 8-бит.
Например (код для семисегментного индикатора):

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

    Led2 = seg7[value % 10];
    value /= 10;
    Led1 = seg7[value % 10];
    value /= 10;
    Led0 = seg7[value % 10];
листинг после компиляции:

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

;Led2 = seg7[value % 10];
    ld	a,#10
    div	x,a
    clrw	x
    ld	xl,a
    ld	a,(_seg7,x)
    ld	_Led2,a
............... и т.д.
на AVR телодвижений побольше будет
Аватара пользователя
Мikа
Потрогал лапой паяльник
Сообщения: 343
Зарегистрирован: Пн апр 01, 2013 15:13:40
Откуда: Москва

Re: Вопросы по С/С++ (СИ)

Сообщение Мikа »

Привет, парни! Сегодня попробовал ещё поплясать с бубном - не получилось.

Между этим:

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

//h=(t/3600);//Вычисление часов
//m=((t-(h*3600))/60);//Вычисление минут
//s=((t-(h*3600))-(m*60));//Вычисление секунд
и последующим переводом в код для индикатора вставлял такое условие:

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

if (h == 10)
{
m=0;
s=0;
}
Эта вставка давала ожидаемые 10:00:00 после 09:59:59.

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

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

if(h == 10 && z == 0)
{
m=0;
s=0;
z=1;
}
Но в таком виде условие полностью игнорировалось и на дисплей после 09:59:59 выводилось 10:68:16.
Я подумал, что не так пишу условие И. (А так ли я его пишу?)

Я сделал проще:

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

if (h == 10)
{
if(z == 0)
{
m=0;
s=0;
z=1;
}
}
Такое условие тоже полностью игнорировалось и на дисплей выводилось 10:68:16.


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

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

        //h=(t/3600);//Вычисление часов
	//m=((t-(h*3600))/60);//Вычисление минут
	//s=((t-(h*3600))-(m*60));//Вычисление секунд
	
	h = t / 3600U;
	t2 = t % 3600U; //Добавив вверху unsigned int t2=0;
	m = t2 / 60U;
	s = t2 % 60U;
И всё заработало. А в чём тут разница? Пока писал пост, обратил внимание на U. Щас попробую свой вариант, но с U.

И дело было в U. Хм, забавно. Надо себе на лбу написать, что это важное и даже обязательное условие к написанию кода.
А кто-то может в 2 словах объяснить, что делает компилятор, когда видит просто число?

Я читал то, что цитировано выше. Только не понятно потому, что и 60 и 3600 прекрасно влезают в int. А
Целая константа, например 1234, имеет тип int.
То есть всё должно было быть ок.

Но при работе функции пересчёта секунд в ЧЧ:ММ:СС с числом 36000 (10 часов) получалась такая тема...
Последний раз редактировалось Мikа Вт фев 18, 2014 10:32:52, всего редактировалось 1 раз.
Почему я здесь и задаю тупые вопросы?
Потому что хочу научиться.
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: Вопросы по С/С++ (СИ)

Сообщение oleg110592 »

Аватара пользователя
Мikа
Потрогал лапой паяльник
Сообщения: 343
Зарегистрирован: Пн апр 01, 2013 15:13:40
Откуда: Москва

Re: Вопросы по С/С++ (СИ)

Сообщение Мikа »

oleg110592, спасибо за ссылку, всё почитал, полезно. Думаю сайт запомню :) Но исходя из прочитанного всё равно не понятно, почему были проблемы с числом 3600 и 60, которые автоматически определяются как int и которым этого int предостаточно.
Почему я здесь и задаю тупые вопросы?
Потому что хочу научиться.
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: Вопросы по С/С++ (СИ)

Сообщение oleg110592 »

на примере для PC компилятора:

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

#include <stdio.h>
 
int r = 256;
 
int main (void)
{
  long long x = 2147483392 * r;
  long long y = 2147483392LL * r;
 
  printf("%lld\n", x);
  printf("%lld\n", y);
 
  return 0;
}
результат:
-65536
549755748352

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

long long x = 2147483392 * r;
В правой части мы видим константу типа int и переменную r типа int. Поэтому умножение над двумя int'ами произойдёт в формате int (т.е. 32-битное умножение, которое вызовет переполнение и откидывание старшей части). Затем при присваивании int'а в long long произойдёт преобразование типов int -> long long (т.е. int32 -> int64)
Ответить

Вернуться в «Разные вопросы по МК»