Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Преобразование типов.  (Прочитано 23754 раз)
0 Пользователей и 2 Гостей смотрят эту тему.
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« : 26-07-2011 12:54 » 

Да, иногда начинаю сомневаться, что хорошо знаю C.

В доке к микроконтроллеру дан пример:

Код: (C)
  1. unsigned int USART_Receive( void )
  2. {
  3.     unsigned char status, resh, resl;
  4. /* Wait for data to be received */
  5.     while ( !(UCSRnA & (1<<RXCn)) )
  6.     ;
  7. /* Get status and 9th bit, then data */
  8. /* from buffer */
  9.     status = UCSRnA;
  10.     resh = UCSRnB;
  11.     resl = UDRn;
  12. /* If error, return -1 */
  13.     if ( status & (1<<FEn)|(1<<DORn)|(1<<UPEn) )
  14.         return -1;
  15. /* Filter the 9th bit, then return */
  16.     resh = (resh >> 1) & 0x01;
  17.     return ((resh << 8) | resl);
  18. }

Интересует 17-ая строчка кода. Строку 1 и 3 я пометил, чтобы было видно типы переменных и возвращаемого значения.

В операторе return стоит выражение в скобках. В выражении участвуют только переменные типа unsigned char. У меня вызвал сомнение сдвиг на 8: разве он приводит к автоматическому расширению типа до unsigned short или unsigned int?

Либо я что-то не знаю, либо в примере ошибка.
« Последнее редактирование: 26-07-2011 12:56 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 26-07-2011 13:25 » 

RXL, тип возвращаемого значения функции - unsigned int. Расширение до этого типа в любом случае где-то должно произойти, и, полагаю, здесь цепочка неявного приведения вниз распутывается.
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #2 : 26-07-2011 13:29 » 

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

В итоге, что же тут реально происходит?

1. Так?
Код: (C)
(unsigned int) ((resh << 8) | resl)

2. Или так?
Код: (C)
((((unsigned int)resh) << 8) | (unsigned int)resl)
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #3 : 26-07-2011 13:29 » 

ISO/IEC 9899:1999 (E):

6.5.7 Bitwise shift operators
Syntax
1 shift-expression:
additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression
Constraints
2 Each of the operands shall have integer type.
Semantics
3 The integer promotions are performed on each of the operands. The type of the result is
that of the promoted left operand. If the value of the right operand is negative or is
greater than or equal to the width of the promoted left operand, the behavior is undefined.
4 The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with
zeros. If E1 has an unsigned type, the value of the result is E1 ´ 2E2, reduced modulo
one more than the maximum value representable in the result type. If E1 has a signed
type and nonnegative value, and E1 ´ 2E2 is representable in the result type, then that is
the resulting value; otherwise, the behavior is undefined.
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 / 2E2. If E1 has a signed type and a negative value, the
resulting value is implementation-defined.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #4 : 26-07-2011 13:33 » 

Иначе говоря, стандарт не предусматривает расширения типа при сдвиге. Это логично. Но может тут другой какой-то фактор есть?
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #5 : 26-07-2011 13:38 » 

If an int can represent all values of the original type, the value is converted to an int;
otherwise, it is converted to an unsigned int. These are called the integer
promotions. All other types are unchanged by the integer promotions.

Это по поводу п.3. Там написано, что оба операнда расширяются.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #6 : 26-07-2011 13:47 » 

Ага - проглядел.
Значит правильный вариант 2 в посте №2?


Меня никогда не тянуло использовать short и char для арифметики, когда есть int. Т.ч. пробел у меня тут явно есть.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #7 : 26-07-2011 15:13 » 

Значит правильный вариант 2 в посте №2?

Похоже, продвижение будет до знакового целого, поскольку unsigned char в него помещается.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #8 : 26-07-2011 21:36 » 

Разве знакового? У нас в исходном unsigned и менять правила расширения вообще не логично!
« Последнее редактирование: 26-07-2011 21:47 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #9 : 26-07-2011 21:42 » 

If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int.

В нашем случае оригинальный тип unsigned char (стр. 3). Его диапазон 0..255 укладывается в диапазон целых знаковых, поэтому сработает первая часть правила.

С вообще в таких случаях недолюбливает беззнаковые типы.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #10 : 26-07-2011 21:48 » 

Ужас какой-то... Проверю в GCC.

Просто в таких случаях C теряет преимущество над ASM. Да, переносимость... Но как-то нелогично вышло.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #11 : 26-07-2011 22:01 » 

Ужас какой-то... Проверю в GCC.

Желательно в режиме С99, я именно этот стандарт цитировал. Не знаю, как в других.

А в чем тут катастрофа? Желание по возможности сохранить знак вполне естественно. Да и 9-разрядный результат до знакового бита все равно не дотянется.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #12 : 26-07-2011 22:10 » 

Если мне не изменяет память, C99 там по умолчанию.

Добавлено через 32 секунды:
Нету знака. Желание "сохранить знак" - ошибка.

"<<" означает сдвиг влево без переноса. Никто не просит расширять его. Тут ведь не константа без указания типа, а определенный тип. Должно быть на выходе 8 бит. ИМХО, конечно.

Понятное дело, что виноват не стандарт языка, а я со своим ожиданием...
« Последнее редактирование: 26-07-2011 22:17 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #13 : 26-07-2011 22:32 » 

Если мне не изменяет память, C99 там по умолчанию.

Лучше проверить, может быть и gnu99. Это довольно близко, но не тождественно.

Должно быть на выходе 8 бит. ИМХО, конечно.

В данном примере тогда в 8 не влезло бы.

Вот здесь:

Код: (C)
    resh = (resh >> 1) & 0x01;
    return ((resh << 8) | resl);
}

сначала в resh  выдирается 8-й бит принятого байта из UCSRnB, а потом добавляется к битам 0..7 UDRn, образуя 9-битное принятое слово. Если бы результат резали до 8 бит, мы бы просто потеряли старший.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #14 : 26-07-2011 22:42 » 

Кстати, Dale,  посмотри в той же доке рядом пример на ассемблере. Еще больший неадекват.

Код:
USART_Receive:
; Wait for data to be received
    sbis UCSRnA, RXCn
    rjmp USART_Receive
; Get status and 9th bit, then data from buffer
    in r18, UCSRnA
    in r17, UCSRnB
    in r16, UDRn
; If error, return -1
    andi r18,(1<<FEn)|(1<<DORn)|(1<<UPEn)
    breq USART_ReceiveNoError
    ldi r17, HIGH(-1)
    ldi r16, LOW(-1)
USART_ReceiveNoError:
; Filter the 9th bit, then return
    lsr r17
    andi r17, 0x01
    ret

Где тут unsigned int и где "return -1"?
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #15 : 27-07-2011 05:17 » 

Еще больший неадекват.

По-моему, почти приемлемо. С поправкой на то, что эти примеры сами авторы никогда толком не проверяют.

Где тут unsigned int

Пара r16, r17, через которую возвращается результат функции.

и где "return -1"?

Код:
    ldi r17, HIGH(-1)
    ldi r16, LOW(-1)

Ну и прошляпили в конце ret, само собой. Еще один аргумент в пользу аксиомы "ни строчки без теста".
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #16 : 27-07-2011 05:37 » 

А, типа int у них длиной 16 бит? Тогда понятно.

А вот с -1 не все гладко - R17 портится же.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #17 : 27-07-2011 05:43 » 

А, типа int у них длиной 16 бит? Тогда понятно.

32-разрядный int обычно реализуют на 32-разрядных архитектурах, иначе накладно. Они же все типы при обработке стараются продвинуть до int.

А вот с -1 не все гладко - R17 портится же.

Ну почему же портится? Используется для дела.

Если результат умещается в байт, возвращают r16. Если в пару, то r16, r17. Если 4 байта (например, float), то r16..r19.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #18 : 27-07-2011 05:54 » 

Возвращаемый тип - unsigned int - значит r17:16.
Вывод: примеры в документации не проверяли.


И так, смотрю, что GCC 4.1.2 сделал.

Код: (C) test_char_int.c
unsigned int USART_Receive( void )
{
    unsigned char resh, resl;

    resh = 0x02;
    resl = 0x88;
    resh = (resh >> 1) & 0x01;
    return ((resh << 8) | resl);
}
 

$ gcc -Wall -std=c99 -S test_char_int.c

Код: (ASM)
USART_Receive:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $16, %esp
        movb    $2, -2(%ebp)  ; resh = 0x02
        movb    $-120, -1(%ebp)  ; resl = 0x88
        movzbl  -2(%ebp), %eax  ; расширение resh до unsigned int
        shrb    %al  ; >> 1
        andl    $1, %eax  ; & 1
        movb    %al, -2(%ebp)  ; в resh, естественно, сохраняется unsigned char
        movzbl  -2(%ebp), %eax  ; расширение resh до unsigned int
        movl    %eax, %edx
        sall    $8, %edx  ; << 8
        movzbl  -1(%ebp), %eax  ; расширение resl до unsigned int
        orl     %edx, %eax  ; resl & resh
        leave
        ret

Используется расширение до unsigned int.
Если поменять возвращаемый тип на unsigned char, то в конце добавляется только отбрасывание старших бит, а вычисления точно такие же.
« Последнее редактирование: 27-07-2011 06:01 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #19 : 27-07-2011 06:41 » new

Используется расширение до unsigned int.

Это может быть результатом оптимизации. Беззнаковый байт можно смело расширять нулями, не противореча стандарту, минуса все равно не может быть.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #20 : 27-07-2011 06:49 » 

Если поменять тип на signed char, то вот:

Код: (ASM)
USART_Receive:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $16, %esp
        movb    $2, -2(%ebp)
        movb    $-120, -1(%ebp)
        movzbl  -2(%ebp), %eax  ; для >> 1 выполняется расширение без знака
        sarb    %al  ; сдвиг в право без знака
        andl    $1, %eax
        movb    %al, -2(%ebp)
        movsbl  -2(%ebp),%eax  ; для << 8 расширяется со знаком
        movl    %eax, %edx
        sall    $8, %edx
        movsbl  -1(%ebp),%eax
        orl     %edx, %eax
        leave
        ret
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #21 : 27-07-2011 07:03 » 

Тоже в общем все логично.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines