RXL
Технический
Администратор
Offline
Пол:
|
|
« : 26-07-2011 12:54 » |
|
Да, иногда начинаю сомневаться, что хорошо знаю C. В доке к микроконтроллеру дан пример: unsigned int USART_Receive( void ) { unsigned char status, resh, resl; /* Wait for data to be received */ while ( !(UCSRnA & (1<<RXCn)) ) ; /* Get status and 9th bit, then data */ /* from buffer */ status = UCSRnA; resh = UCSRnB; resl = UDRn; /* If error, return -1 */ if ( status & (1<<FEn)|(1<<DORn)|(1<<UPEn) ) return -1; /* Filter the 9th bit, then return */ resh = (resh >> 1) & 0x01; return ((resh << 8) | resl); }
Интересует 17-ая строчка кода. Строку 1 и 3 я пометил, чтобы было видно типы переменных и возвращаемого значения. В операторе return стоит выражение в скобках. В выражении участвуют только переменные типа unsigned char. У меня вызвал сомнение сдвиг на 8: разве он приводит к автоматическому расширению типа до unsigned short или unsigned int? Либо я что-то не знаю, либо в примере ошибка.
|
|
« Последнее редактирование: 26-07-2011 12:56 от RXL »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Вад
|
|
« Ответ #1 : 26-07-2011 13:25 » |
|
RXL, тип возвращаемого значения функции - unsigned int. Расширение до этого типа в любом случае где-то должно произойти, и, полагаю, здесь цепочка неявного приведения вниз распутывается.
|
|
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #2 : 26-07-2011 13:29 » |
|
Меня смущает то, что выражение находится в скобках и приведение к типу возвращаемого значения на этапе выполнения сдвига быть не должно. Конечно, если я не ошибаюсь. В итоге, что же тут реально происходит? 1. Так? (unsigned int) ((resh << 8) | resl) 2. Или так? ((((unsigned int)resh) << 8) | (unsigned int)resl)
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Dale
|
|
« Ответ #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
Технический
Администратор
Offline
Пол:
|
|
« Ответ #4 : 26-07-2011 13:33 » |
|
Иначе говоря, стандарт не предусматривает расширения типа при сдвиге. Это логично. Но может тут другой какой-то фактор есть?
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Dale
|
|
« Ответ #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
Технический
Администратор
Offline
Пол:
|
|
« Ответ #6 : 26-07-2011 13:47 » |
|
Ага - проглядел. Значит правильный вариант 2 в посте №2?
Меня никогда не тянуло использовать short и char для арифметики, когда есть int. Т.ч. пробел у меня тут явно есть.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Dale
|
|
« Ответ #7 : 26-07-2011 15:13 » |
|
Значит правильный вариант 2 в посте №2? Похоже, продвижение будет до знакового целого, поскольку unsigned char в него помещается.
|
|
|
Записан
|
Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.
Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard
Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #8 : 26-07-2011 21:36 » |
|
Разве знакового? У нас в исходном unsigned и менять правила расширения вообще не логично!
|
|
« Последнее редактирование: 26-07-2011 21:47 от RXL »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Dale
|
|
« Ответ #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
Технический
Администратор
Offline
Пол:
|
|
« Ответ #10 : 26-07-2011 21:48 » |
|
Ужас какой-то... Проверю в GCC.
Просто в таких случаях C теряет преимущество над ASM. Да, переносимость... Но как-то нелогично вышло.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Dale
|
|
« Ответ #11 : 26-07-2011 22:01 » |
|
Ужас какой-то... Проверю в GCC. Желательно в режиме С99, я именно этот стандарт цитировал. Не знаю, как в других. А в чем тут катастрофа? Желание по возможности сохранить знак вполне естественно. Да и 9-разрядный результат до знакового бита все равно не дотянется.
|
|
|
Записан
|
Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.
Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard
Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #12 : 26-07-2011 22:10 » |
|
Если мне не изменяет память, C99 там по умолчанию.
Добавлено через 32 секунды: Нету знака. Желание "сохранить знак" - ошибка.
"<<" означает сдвиг влево без переноса. Никто не просит расширять его. Тут ведь не константа без указания типа, а определенный тип. Должно быть на выходе 8 бит. ИМХО, конечно.
Понятное дело, что виноват не стандарт языка, а я со своим ожиданием...
|
|
« Последнее редактирование: 26-07-2011 22:17 от RXL »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Dale
|
|
« Ответ #13 : 26-07-2011 22:32 » |
|
Если мне не изменяет память, C99 там по умолчанию. Лучше проверить, может быть и gnu99. Это довольно близко, но не тождественно. Должно быть на выходе 8 бит. ИМХО, конечно. В данном примере тогда в 8 не влезло бы. Вот здесь: resh = (resh >> 1) & 0x01; return ((resh << 8) | resl); } сначала в resh выдирается 8-й бит принятого байта из UCSRnB, а потом добавляется к битам 0..7 UDRn, образуя 9-битное принятое слово. Если бы результат резали до 8 бит, мы бы просто потеряли старший.
|
|
|
Записан
|
Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.
Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard
Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #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
|
|
« Ответ #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
Технический
Администратор
Offline
Пол:
|
|
« Ответ #16 : 27-07-2011 05:37 » |
|
А, типа int у них длиной 16 бит? Тогда понятно.
А вот с -1 не все гладко - R17 портится же.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Dale
|
|
« Ответ #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
Технический
Администратор
Offline
Пол:
|
|
« Ответ #18 : 27-07-2011 05:54 » |
|
Возвращаемый тип - unsigned int - значит r17:16. Вывод: примеры в документации не проверяли. И так, смотрю, что GCC 4.1.2 сделал. 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 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
|
|
« Ответ #19 : 27-07-2011 06:41 » |
|
Используется расширение до unsigned int. Это может быть результатом оптимизации. Беззнаковый байт можно смело расширять нулями, не противореча стандарту, минуса все равно не может быть.
|
|
|
Записан
|
Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.
Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard
Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #20 : 27-07-2011 06:49 » |
|
Если поменять тип на signed char, то вот: 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
|
|
« Ответ #21 : 27-07-2011 07:03 » |
|
Тоже в общем все логично.
|
|
|
Записан
|
Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.
Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard
Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
|
|
|
|