|
>>, Что означает эта запись? |
|
|
|
Jul 1 2009, 16:01
|
Участник

Группа: Участник
Сообщений: 29
Регистрация: 24-06-09
Пользователь №: 50 601

|
Братцы, я с языком си знаком слабовато. Что означает вот эта запись? Подскажите пожалуйста.
*pDMA_DBP = (unsigned short)((unsigned int)sSPORT0_TX_Descriptor >> 16);
|
|
|
|
|
Jul 1 2009, 23:42
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
>> - обозначает сдвиг вправо. x >> n сдвиг переменной x вправо на n разрядов. пример: 1100 >> 1 = 0110 Цитата арифметический сдвиг вправо Всегда думал что над (unsigned int) может производиться только строго логический сдвиг. Арифметический же должен выполняться исключительно над (signed) переменными. собсно не сложно в этом убедиться: signed int x1 = 0x80000000; unsigned int x2 = 0x80000000; printf("x1 >> 3 = 0x%x\nx2 >> 3 = 0x%x", x1 >> 3, x2 >> 3); результат: x1 >> 3 = 0xF0000000 - арифметический сдвиг x2 >> 3 = 0x10000000 - логический сдвиг
|
|
|
|
|
Jul 2 2009, 02:16
|

Гуру
     
Группа: Участник
Сообщений: 2 254
Регистрация: 4-05-07
Из: Moscow
Пользователь №: 27 515

|
>> в Сях - это деление на степень двойки. Вот так проще всего описать. Скажем, -4 сдвинуть вправо будет -2. 4 сдвинуть вправо будет 2. (А побитнно если рассматривать эти числа будет очень существенная разница. Команда арифметического сдвига дублирует при сдвиге старший бит. И компилятор сам решает какую команду применить).
Посему, если работаем с битами, масками, управляющими словами, адресами регистров - не надо использовать ЗНАКОВЫЕ объявления. Вернее, использвать можно, но только ТОЧНО зная, что делаешь и зачем тебе это нужно.
У меня вот такое правило. Переменные объявляю всегда unsigned. Если уж объявляю signed - то уж с конкретной явной целью. К примеру буду вычислять что=нибудь, что имеет знак, или потребуется сравнивать что-то с чем-то и потребуется значение разницы.
Короче, куда ни кинь - кругом надо всегда иметь ввиду знаковость переменной.
Сообщение отредактировал DpInRock - Jul 2 2009, 02:50
--------------------
On the road again (Canned Heat)
|
|
|
|
|
Jul 2 2009, 10:30
|

Профессионал
    
Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357

|
Цитата(defunct @ Jul 2 2009, 03:42)  >> - обозначает сдвиг вправо.
x >> n сдвиг переменной x вправо на n разрядов.
пример: 1100 >> 1 = 0110 Правильнее (чтобы не вводить людей в заблуждение) написать так: 00001100 >> 1 = 00000110 Потому что если число знаковое, то сдвиг распространяет знак: 1100 >> 1 = 1110 Правда, если говорить строго, то это implementation defined, но в большинстве нормальных компиляторов сделано именно так. Цитата(DpInRock @ Jul 2 2009, 06:16)  >> в Сях - это деление на степень двойки. Вот так проще всего описать. Ни в коем случае. Это грубая, хотя и очень распространеная ошибка. -3 / 2 = -1 -3 >> 1 = -2 Так понятно?
Сообщение отредактировал 777777 - Jul 2 2009, 10:32
|
|
|
|
|
Jul 2 2009, 11:02
|

Гуру
     
Группа: Участник
Сообщений: 2 254
Регистрация: 4-05-07
Из: Moscow
Пользователь №: 27 515

|
Цитата Вот так проще всего описать. Ключевое слово. А начни вы объяснять с этого примера, то кранты бы пришли человеку. Поэтому и прозвучал совет не делать неарифметических операций над знаковыми.
--------------------
On the road again (Canned Heat)
|
|
|
|
|
Jul 2 2009, 12:12
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(777777 @ Jul 2 2009, 13:30)  Правильнее (чтобы не вводить людей в заблуждение) написать так: 00001100 >> 1 = 00000110 А ну да, если допустить что бывают 4-х битовые знаковые. Однако, вы не утруждаете себя читать посты до конца. Цитата Правда, если говорить строго, то это implementation defined, но в большинстве нормальных компиляторов сделано именно так. Если говорить строго, то лучше сразу обратиться непосредственно к стандарту. [#5] The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 divided by the quantity, 2 raised to the power E2. If E1 has a signed type and a negative value, the resulting value is implementation- defined. Чтобы было ясно, что именно является implementation defined. Cобсно определение которое предложил DpInRock, совпадает со стандартом. а не Цитата Это грубая, хотя и очень распространеная ошибка. как вы говорите.
|
|
|
|
|
Jul 3 2009, 10:44
|

Профессионал
    
Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357

|
Цитата(defunct @ Jul 2 2009, 16:12)  Cобсно определение которое предложил DpInRock, совпадает со стандартом. Правда он не уточнил, что это справедливо только для беззнаковых. Ну да, он же написал что использует только их. Цитата(defunct @ Jul 2 2009, 16:12)  а не Цитата Это грубая, хотя и очень распространеная ошибка. как вы говорите. Если следовать стандарту, то получается, что отрицательные вообще нельзя сдвигать, так как результат непредсказуем. Тем не менее все компиляторы, имеющиеся у меня под рукой, выдали результат: -3 / 2 = -1 -3 >> 1 = -2 Так что сдвиг - это вовсе не то же самое, что и целочисленное деление.
|
|
|
|
|
Jul 3 2009, 17:21
|

Профессионал
    
Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357

|
Цитата(defunct @ Jul 3 2009, 18:29)  Разница то с целочисленным делением в округлении только, При целочисленном делении не выполняется округления. Это строгая математическая операция, которая дает в результате частное и остаток. Цитата(defunct @ Jul 3 2009, 18:29)  которое при >> (как для положительных так и для отрицательных) делается всегда к меньшему. При сдвиге тем более нет смысла говорить об округлении. Это - лишь сдвиг битов. И использовать его нужно только если требуются какие-то манипуляции с битами. Впрочем, важно понимать, что деление и сдвиг не одно и то же и не использовать сдвиг для деления - оптимизирующий компилятор сам заменит его на сдвиг если это можно. А если нельзя - то не заменит!
|
|
|
|
|
Jul 24 2009, 07:38
|
Участник

Группа: Участник
Сообщений: 51
Регистрация: 13-01-06
Из: Санкт-Петербург
Пользователь №: 13 154

|
Цитата Если следовать стандарту, то получается, что отрицательные вообще нельзя сдвигать, так как результат непредсказуем. Тем не менее все компиляторы, имеющиеся у меня под рукой, выдали результат: Результат предсказуем как грабли и прописан в стандарте  В языке С для операции правого сдвига для знаковых типов есть определенное правило. Если старший бит равен нулю, то левые поля заполняются нулями. Если старший бит равен единице, то поля заполняются единицами. Отсюда следствие - положительные числа сдвигаются "как есть", а отрицательные числа, поскольку имеют в старшем бите единицу, сдвигаются вправо с заполнением единицей. Пример: 0х40 >> 2 == 0x10; 0xC0 >> 2 == 0xF0; 0хС0 в десятичном представлении для знакового типа - это -64, а 0xF0 - это -16.
--------------------
Все врут (с) /M.D.House/
|
|
|
|
|
Jul 24 2009, 07:53
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(Dreamer @ Jul 24 2009, 10:38)  Отсюда следствие - положительные числа сдвигаются "как есть", а отрицательные числа, поскольку имеют в старшем бите единицу, сдвигаются вправо с заполнением единицей. Пример: 0х40 >> 2 == 0x10; 0xC0 >> 2 == 0xF0; С чего бы вдруг 0xC0 быть байтом? Запись 0xC0 означает лишь шестандцатеричную форму записи, но никак не ограничение одним байтом. Думаете, что 0x00C0 другое число? - Нет, то же самое! Константы такого рода считаются, как int-значения, а не char. А int это обычно 2 байта, а не один. Причем даже для 8-битных микропроцессоров (AVR). Поэтому старший бит у этого числа нулевой. А потому 0xC0 >> 2 == 0x30;
|
|
|
|
|
Jul 24 2009, 08:14
|
Участник

Группа: Участник
Сообщений: 51
Регистрация: 13-01-06
Из: Санкт-Петербург
Пользователь №: 13 154

|
Цитата С чего бы вдруг 0xC0 быть байтом? С того, что его можно объявить как signed char. Мой пример именно для signed char. Цитата Константы такого рода считаются, как int-значения, а не char. А int это обычно 2 байта, а не один. Не-а. Обычно длина типа int соответствует разрядности процессора, для которого сделан компилятор. Для 32разрядных int будет 4 байта, для 16разрядных - 2 байта. Константы, явно заданные в выражении, действительно являются типом int. Я оговорился и не написал, что пример придназначен для типа signed char. Цитата А потому 0xC0 >> 2 == 0x30 Хорошо. Тогда пример специально для Вас:  0хС000 >> 2 == 0xF000 (Конкретно для знакового 2байтового типа). Вот вам еще пример кода: Код char c = 0xC0; int i = c; i>>=2; char и int в настройках компилятора стоят как знаковые. Как вы думаете, чему будет равно i после выполнения кода? Думаете, 0x0030? Не-а. Результат будет равен 0хFFF0.
--------------------
Все врут (с) /M.D.House/
|
|
|
|
|
Jul 24 2009, 08:39
|
Участник

Группа: Участник
Сообщений: 51
Регистрация: 13-01-06
Из: Санкт-Петербург
Пользователь №: 13 154

|
Цитата Если это char, да еще и знаковый, то возражений у меня нет. Я же имела в виду, что выражение if (0xC0 >> 2 == 0xF0) было бы расценено IAR-компилятором как ложное Ну у меня возражений тоже нет  Я написал-то пример не к словам о приведению типов, а к высказанному в этой ветке мнению, что сдвиг вправо у отрицательных чисел непредсказуем. А правило тем-не менее есть и оно стандартное. Цитата P.S. IAR-компилятор для AVR8 понимает int, как двухбайтное знаковое целое, несмотря на то, что регистры имеют разрядность один байт. Да, для Keil51 у int тоже два байта, хотя процессор там восьмиразрядный. Это не вяжется с тем правилом, котрое я процетировал, но я его видел в литературе очень много раз.
--------------------
Все врут (с) /M.D.House/
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|