Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Тип данных в Кейле
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Все остальные микроконтроллеры > MCS51
Desntal
подскажите начинающему, к какому типу данных правильно отнести число 900 . Дело в том что кейл одинаково отрабатывает и "uint" и "uchar" с подобным числом и в железе все работает правильно, хотя , если я не ошибаюсь, это двухбайтовая величина и должна быть типа "short"
scifi
Вы что-то другое хотели спросить, потому что этот вопрос не имеет особого смысла.
Число не имеет типа в языке Си. Тип имеет выражение, к выражениям относятся и константы. А константу можно написать по-разному. Примеры: 900, 900L, 900UL, (short)900, (char)900. Это всё константы, имеющие разные типы. Причём последняя эквивалентна (char)-124 или (char)132 в зависимости от того, имеет ли знак тип char (это тоже по-разному бывает).
Desntal
поясню вопрос: с термометра ds18b20 считываются два байта данных о температуре, после мат обработки отсеивается часть данных(о знаке температуры), оставшаяся часть принимает описанный выше вид и заносится в переменную. Так при объявлении переменной какой тип данных использовать?
пс.
я считал, что указание типа обязывает компилятор резервировать соответствующее количество ячеек памяти...
Палыч
Цитата(Desntal @ Jun 10 2011, 10:10) *
какой тип данных использовать?
Для этого нужно знать диапазон возможных значений
Desntal
дополнение к вопросу.
фрагмент кода:

tval=tval*(0.625);//
return(tval);

после этой операции tval может принимать значение от 000 до 1200, далее идет сравнение с переменной содержащей число из этого диапазона.

извиняюсь, ошибка. Правильно от 0000 до 1200.
Палыч
Цитата(Desntal @ Jun 10 2011, 10:46) *
после этой операции tval может принимать значение от 000 до 1200
Вы хотите правильно объявить переменную tval? А, какой диапазон значений этой переменной до этой операции? От 0 до 1920? Тогда - unsigned int...

Применять операции с плавающей точкой в МК - очень расточительно. Достаточно привести 0.625 к виду 5/8 (деление на 8 целого = сдвиг вправо на 3), тогда
Код
tval= (5 * tval) >> 3;
scifi
По-моему, этот топик просится, чтобы его перенесли в раздел для начинающих.
Desntal
да, объяснить на пальцах трудно. может так понятнее:

...

unsigned ??? data tval;//???- это тип данных
unsigned ??? data tUstavka;
...
tval=tval*0.625;
....
if(tval<=tUstavka)
...

сомнение вызвало то, что в описании типов данных в имеющейся литературе, размер типа uchar 255, а тип uint зависит от разрядности процессора, в данном случае для С51 8 разрядов, значит тоже 255, но здесь мне говорят что uint больше тысячи, запутали вконец... где истина?
Палыч
Цитата(Desntal @ Jun 10 2011, 14:55) *
для С51 8 разрядов
Абсолютно неверно. Можно посмотреть файл limits.h - в нем приведены границы диапазонов значений для разных типов данных.

P.S. А ещё можно посмотреть в документации: файл с51.chm; смотреть "Language Extensions->Data Types"
Desntal
Палыч, спасибо, просмотрел файл, теперь все ясно можно смело использовать uint.
Палыч
А, к моему совету (см. пост #6) по поводу исключения операций с плавающей запятой - не прислушались... Зря.
koyodza
Цитата(Палыч @ Jun 10 2011, 10:11) *
Вы хотите правильно объявить переменную tval? А, какой диапазон значений этой переменной до этой операции? От 0 до 1920? Тогда - unsigned int...

В корне неверно.
Если unsigned int умножать на 0,625, то в результате всегда будет 0
Потому как (int)0,625 будет 0
Если нужно получать не 0, то нужно использовать float (или double, если нужно, и если оно поддерживается)

Цитата(Палыч @ Jun 10 2011, 10:11) *
Применять операции с плавающей точкой в МК - очень расточительно. Достаточно привести 0.625 к виду 5/8 (деление на 8 целого = сдвиг вправо на 3), тогда
Код
tval= (5 * tval) >> 3;

Это правильно, без особой необходимости лучше плавучку на МК не использовать, здесь вам не тут, это не х86 с сопроцессором, однако.
Тем более когда речь идёт об умножении на константу
Палыч
Цитата(koyodza @ Jun 29 2011, 23:49) *
В корне неверно.
Если unsigned int умножать на 0,625, то в результате всегда будет 0
Потому как (int)0,625 будет 0
Вот те - раз...
В выражении
tval=tval*0.625 , где tval целого типа,
константа 0.625 - вещественная; значение tval приводится к вещественному типу; производится умножение двух вещественных; результат приводится к целому; присваивается tval...
koyodza
Цитата(Палыч @ Jun 30 2011, 11:59) *
Вот те - раз...
В выражении
tval=tval*0.625 , где tval целого типа,
константа 0.625 - вещественная; значение tval приводится к вещественному типу; производится умножение двух вещественных; результат приводится к целому; присваивается tval...

Да, Вы правы, в данном случае происходит неявное приведение к double и обратно. Только вот оно надо?

В любом случае подобных конструкций лучше избегать
Палыч
Цитата(koyodza @ Jul 12 2011, 00:51) *
В любом случае подобных конструкций лучше избегать

Совершенно верно. Тем более, что значение 0,625 можно представить в виде "красивой" дроби 5/8, с соответственным упрощением умножения на неё, о чём выше и сказано.
demiurg_spb
К слову. Все современные компиляторы самостоятельно будут использовать сдвиг вместо деления когда это оправдано, так что (x*5)/8 совершенно равнозначно (х*5)>>3, но читается проще.
Палыч
Цитата(demiurg_spb @ Jul 12 2011, 11:02) *
Все современные компиляторы самостоятельно будут использовать сдвиг вместо деления когда это оправдано
Возможно, но иногда удивляешся коду, который нагенерил "современный" компилятор...

Цитата(demiurg_spb @ Jul 12 2011, 11:02) *
(x*5)/8 совершенно равнозначно (х*5)>>3
А, вот тут я с Вами не согласен. Насколько я помню (поправьте, если я не прав): раставленные в выражении (x*5)/8 скобочки никак не определяют последовательность выполнения операций. Поскольку приоритеты операций * и / одинаковые, то выражение (x*5)/8 с точки зрения компилятора в соответствии со стандартом эквивалентно x*5/8 или даже x*(5/8). Компилятор вправе на этапе трансляции вычислить часть выражения, если операнды - константы. Но, поскольку 5/8 равно нулю, то можно получить результат далёкий от ожидаемого...
При вычислении выражения (х*5)>>3 последовательность вычислений однозначно определена приоритетами.
scifi
Цитата(Палыч @ Jul 12 2011, 12:48) *
Насколько я помню (поправьте, если я не прав): раставленные в выражении (x*5)/8 скобочки никак не определяют последовательность выполнения операций.

Поправляю. Вы не правы. И даже просто с позиции здравого смысла: нафиг скобки вообще нужны, если они ни на что не влияют?
demiurg_spb
Проверил живьём на максимальном уровне оптимизации выражение
Код
uint32_t x;
x = (x*5)/8;
превратилось в
Код
0x08001C88 4C06      LDR      r4,[pc,#24]; @0x08001CA4
0x08001C8A 6820      LDR      r0,[r4,#0x00]
0x08001C8C EB000080  ADD      r0,r0,r0,LSL #2
0x08001C90 08C0      LSRS     r0,r0,#3
0x08001C92 6020      STR      r0,[r4,#0x00]

Всё как и ожидалось сначала умножил на 5 (хитро сложив и сдвинув), а потом поделил на 8 (сдвинув направо на 3).
Стандарта в части скобочек не могу процитировать, но полагаю что scifi близок к истине.
Палыч
Цитата(scifi @ Jul 12 2011, 13:22) *
нафиг скобки вообще нужны, если они ни на что не влияют?
Я не утверждал, что скобки "ни на что не влияют". Например в выражении (х*5)>>3 они (скобки) очень даже "влияют". А, вот, в выражении (x*5)/8 компилятор вправе их игнорировать...
Пример попроще: выражение (х+2)-1. Как Вы думаете: компилятор сгенерирует 1) выполнение двух операций или 2) преобразует в х+(2-1) и, соответственно, вычислит на этапе трансляции (2-1) и, в конце концов, получим х+1 ?
demiurg_spb
Я думаю что Вы оба правы. Когда можно упростить выражение без изменения сути, это будет сделано компилятором несомненно.
Но в примере с умножением и сдвигом никаких упрощений быть не может для целочисленных не кратных чисел.
Мне вот на ум приходит вредный совет для начинающих: не уверен в приоритетах операций - расставь скобочки.
И это правило работало всегда без исключений.
scifi
Цитата(Палыч @ Jul 12 2011, 13:43) *
А, вот, в выражении (x*5)/8 компилятор вправе их игнорировать...

Ну, если мне не верите, проверьте сами. По-вашему выражение (x*5)/8 даёт результат 0 вне зависимости от значения x. Это легко проверить. Или Вы хотите сказать, что результат выражения зависит от уровня оптимизации? Тогда это вообще нонсенс. Кому нужна оптимизация, коверкающая результат простейшего арифметического выражения? Не говоря уже о том, что это просто противоречит стандарту языка Си.

Добавление:
Да, в стандарте языка указаны случаи, в которых порядок вычисления не определён. Например, порядок вычисления аргументов функции. Или операндов побитового И или ИЛИ (& или |). Но (x*5)/8 - не тот случай. Стандарт чётко описывает, что сначала идёт умножение, а потом - деление (кстати, и без скобок тоже, по правилам приоритетов операторов). Причём умножение и деление происходят в "абстрактной машине". Что там нагенерит компилятор - его дело, лишь бы результат был бы такой же, как в "абстрактной машине". Как мы видели, он может нагенерить сдвиги и сложения. Или вообще подставить константу, если результат выражения известен на этапе компиляции.
GetSmart
Цитата(demiurg_spb @ Jul 12 2011, 14:50) *
Я думаю что Вы оба правы. Когда можно упростить выражение без изменения сути, это будет сделано компилятором несомненно.

Докажите что ли на конкретном примере кода и компилятора. А так - очередной "вредный совет" или версия.
demiurg_spb
Цитата(GetSmart @ Jul 12 2011, 13:56) *
Докажите что ли на конкретном примере кода и компилятора. А так - очередной "вредный совет" или версия.
Для себя уже давно доказал на разных компиляторах...
Вы хотите увидеть как x=(x-1)+2 превратится в x+=1 ???
GetSmart
Цитата(demiurg_spb @ Jul 12 2011, 15:03) *
Для себя уже давно доказал. Для разных компиляторов...

То есть какой-то компилятор может "наплевать" на скобки? Какой?

Upd.
Проверил на IAR-е.
Сложения и вычитания костант, идущие друг за другом даже за скобками он упрощает. Потому как переполнения на них не влияют. А умножения и деления нет.
scifi
Цитата(GetSmart @ Jul 12 2011, 14:18) *
То есть какой-то компилятор может "наплевать" на скобки? Какой?

Как я понял, demiurg_spb и не намекает на то, что компилятор может наплевать на скобки. Напротив:
Цитата(demiurg_spb @ Jul 12 2011, 13:50) *
Когда можно упростить выражение без изменения сути, это будет сделано компилятором несомненно.

В данном случае перестановка скобок (x*5)/8 -> x*(5/8) очень даже изменяет суть, а потому компилятору не разрешена. Что мы и пытаемся объяснить Палычу.
Не соглашусь только, что компилятор применит оптимизацию "несомненно", так как видел немало тупых компиляторов.
Палыч
Цитата(scifi @ Jul 12 2011, 13:55) *
Ну, если мне не верите, проверьте сами. По-вашему выражение (x*5)/8 даёт результат 0 вне зависимости от значения x. Это легко проверить. Или Вы хотите сказать, что результат выражения зависит от уровня оптимизации?
Нет, зависит от "уровня" трансляторописателей, вернее их понимания "духа и буквы" стандарта.

Цитата(scifi @ Jul 12 2011, 13:55) *
Стандарт чётко описывает, что сначала идёт умножение, а потом - деление (кстати, и без скобок тоже, по правилам приоритетов операторов).
Тут с Вами не соглашусь. Приоритет всех мультипликативных операций (*, /, %) одинаков.

Цитата(GetSmart @ Jul 12 2011, 14:18) *
То есть какой-то компилятор может "наплевать" на скобки?
В некоторых случаях - да, может "наплевать". Речь идёт о операциях с одинаковым приоритетом в скобках и за скобками. Нет времени искать точную формулировку в стандарте, но, по-памяти: "порядок выполнения операций может быть изменён, если это не приводит к изменению значения выражения". С учетом того, что при выполнении операций могут возникать всякие-разные "неприятности" (типа переполнения результата), то понятие "неизменный результат" становится очень расплывчатым, и тут - простор для трансляторописателей...
GetSmart
Цитата(Палыч @ Jul 12 2011, 15:49) *
Нет времени искать точную формулировку в стандарте, но, по-памяти: "порядок выполнения операций может быть изменён, если это не приводит к изменению значения выражения".

Было такое. Но это исключительно когда нет скобок. Не выдумывайте свою интерпретацию


Цитата(Палыч @ Jul 12 2011, 15:49) *
В некоторых случаях - да, может "наплевать". Речь идёт о операциях с одинаковым приоритетом в скобках и за скобками.

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

По логике, это можно делать, когда перепонения при исполнении операций не могут повлиять на результат. То есть то же, что и в школьной математике, но с учётом ограниченности (временных) переменных. Это подходит к сложениям/вычитаниям, лог операциям, но не относится к сдвигам, умнодениям/делениям.
scifi
Цитата(Палыч @ Jul 12 2011, 14:49) *
Нет, зависит от "уровня" трансляторописателей, вернее их понимания "духа и буквы" стандарта.

То есть кто-то может неправильно понять стандарт и, соответвственно, написать компилятор с глюком. Спасибо за напоминание об это очевидном факте.

Цитата(Палыч @ Jul 12 2011, 14:49) *
Тут с Вами не соглашусь. Приоритет всех мультипликативных операций (*, /, %) одинаков.

Я имел в виду в данном конкретном выражении: (x*5)/8.

Цитата(Палыч @ Jul 12 2011, 14:49) *
Нет времени искать точную формулировку в стандарте, но, по-памяти: "порядок выполнения операций может быть изменён, если это не приводит к изменению значения выражения".

Нет нужды, я уже нашёл:
Цитата
The semantic descriptions in this International Standard describe the behavior of an abstract machine in which issues of optimization are irrelevant.
...
In the abstract machine, all expressions are evaluated as specified by the semantics. An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced (including any caused by calling a function or accessing a volatile object).


Цитата(Палыч @ Jul 12 2011, 14:49) *
С учетом того, что при выполнении операций могут возникать всякие-разные "неприятности" (типа переполнения результата), то понятие "неизменный результат" становится очень расплывчатым, и тут - простор для трансляторописателей...

В случае с целыми беззнаковыми числами никакой расплывчатости нет:
Цитата
A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

Не разобравшись в ситуации, не давайте вредных советов. Вдруг неокрепшие умы всерьёз воспримут.
Палыч
Цитата(GetSmart @ Jul 12 2011, 14:59) *
исключительно когда нет скобок
Действительно - признаю: в стандарте порядок операций может быть изменён, если нет скобок (т.е. нет Primary expressions, имеющих при вычислениях наивысший приоритет). Однако стандарт и тут оставляет "лазейку": абсолютно вся оптимизация отдана на откуп компиляторописателям. Забавно, что IAR оптимизирует даже при выключенной оптимизации. Например, выражение (x+1)+(y+1) оптимизирует до x+y+2
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.