Пишу в среде CodeWarrior для контроллеров freescale HC(S) Есть макрос #define EnableMC13192Timer1(u32Timeout) \ SPIDrvWrite(0x1B,(UINT16)((u32Timeout >>16) &0x000000FF) |0x000080FF); \ SPIDrvWrite(0x1C,(UINT16)( u32Timeout &0x0000FFFF)); \ SPIDrvWrite(0x1B,(UINT16)((u32Timeout >>16) &0x000000FF)); \ SPIDrvWrite(0x1C,(UINT16)( u32Timeout &0x0000FFFF)); Есть константы #define NUMBER_OF_SENSORS 2 #define TIMEOUT_TO_SENSORS 30000 Вызываю макрос 1)EnableMC13192Timer1(60000); 2)EnableMC13192Timer1(NUMBER_OF_SENSORS*TIMEOUT_TO_SENSORS); В первом случае все работает и компилятор выдает 0073 a61b LDA #27 0075 4580ff LDHX #-32513 0078 cd0000 JSR SPIDrvWrite 007b a61c LDA #28 007d 45ea60 LDHX #-5536 0080 cd0000 JSR SPIDrvWrite 0083 a61b LDA #27 0085 5f CLRX 0086 8c CLRH 0087 cd0000 JSR SPIDrvWrite 008a ae60 LDX #96 008c a6ea LDA #-22 008e 87 PSHA 008f 8a PULH 0090 a61c LDA #28 0092 cd0000 JSR SPIDrvWrite Во втором случае не работает и получаю 0073 a61b LDA #27 0075 4580ff LDHX #-32513 0078 cd0000 JSR SPIDrvWrite 007b a61c LDA #28 007d 45ea60 LDHX #-5536 0080 cd0000 JSR SPIDrvWrite 0083 a61b LDA #27 0085 aeff LDX #-1 0087 8c CLRH 0088 cd0000 JSR SPIDrvWrite 008b ae60 LDX #96 008d a6ea LDA #-22 008f 87 PSHA 0090 8a PULH 0091 a61c LDA #28 0093 cd0000 JSR SPIDrvWrite Различие в команде по адресу 0x0085. Почему такая несправедливость и есть ли возможность ее поправить не прибегая к написанию на ассемблере (влом!!!)
mha С такой железкой не знаком, но если у нее int 16-бит, то попробуй Код (Text): #define NUMBER_OF_SENSORS 2LU #define TIMEOUT_TO_SENSORS 30000LU и еще - чтобы не было проблем - всегда в определении макроса бери параметры в скобки, т.е. Код (Text): #define EnableMC13192Timer1(u32Timeout) \ SPIDrvWrite(0x1B,(UINT16)(((u32Timeout) >>16) &0x000000FF) |0x000080FF); \ SPIDrvWrite(0x1C,(UINT16)( (u32Timeout) &0x0000FFFF)); \ SPIDrvWrite(0x1B,(UINT16)(((u32Timeout) >>16) &0x000000FF)); \ SPIDrvWrite(0x1C,(UINT16)( (u32Timeout) &0x0000FFFF)); но в данном случае это несущественно.
>> (u32Timeout >>16) Оператор >> имеет приоритет выше чем *. Поэтому нужно так: ((u32Timeout) >>16) ЗЫ: Опередили
Quantum Нет, вот как раз наоборот, именно поэтому я и написал, что в ДАННОМ случае несущественно. По приоритетам: * / % + - << >> & ^ | < <= > >= == != && ||
Ustus Верно, хотя в данном случае приоритеты одинаковые, т.к. >> 16 можно расценивать как деление на 2<sup>16</sup>. Возможно баг именно из-за деления, т.к. в первом вырианте очевидно, что операнд 16-битное беззнаковое число. Во втором случае это уже не очевидно и, скорее всего, сдвиг проводится арифметический, т.е. с сохранением знака. Поэтому результат -1, что после and даёт 0x00FF. mha Кроме скобок добавьте каст (UINT16) к u32Timeout.
Баг при использовании различных операций над константами при вызове макроса или процедуры компилятор также в некоторых случаях записывает неправильные значения в стек. Можно ли например в studio например влиять на повеение компилятора при вызове процедур кроме задания параметров _stdcall и тд. Както можно управлять компилятором С.
mha А что ещё может понадобиться поменять в процедуре, кроме имени, генерации пролога/эпилога и соглашения о вызове? Студия позволяет всё это менять. О некоторых экзотических соглашениях она не знает или не желает знать, но их можно написать на асме и заинлайнить. cl.exe позволяет управлять практически всеми этапами компиляции через параметры командной строки. В сети где-то есть список даже недокументированных параметров, коих очень-очень много. Но начинать лучше с документированных -> msdn.
mha Какой именно баг? Какие значения? Компилятор редко записывает неправильные значения Он может просто неправильно вас понять... Quantum Увы, компилятору вы это доказать не сможете Для него сдвиг - всегда сдвиг...
Ustus Понятно, что выдвинутая мною теория не выдерживает критики, но другого объяснения такому явному багу со знаком я не вижу. Имеем 2 явно беззнаковых операнда, операцию умножения и сдвиг. Никакого намёка на знаковость в этом выражении нет, но хвалёный CodeWarrior решил иначе. Забавно, что когда-то читал на их сайте статью, в которой они утверждали, что пользоваться бесплатными компиляторами, вроде GCC, небезопасно из-за возможных ошибок компиляции
mha Есть ли в CodeWarrior генерация файла с результатами работы препроцессора (типа /P в VC++) ? Попробуй указать явно беззнаковость всех констант например 0x000000FFU
да, нету, но я имел в виду, что, напр., литерал `5' имеет в C тип int. и если я напишу: unsigned var = 5; то это подразумевает преобразование 5 типа int, к 5 типа unsigned. Чем не дефолтовый тип
r90 Если совсем точно по стандарту - то для целочисленного ДЕСЯТИЧНОГО литерала (если не используется явное указание суффиксом) тип является int, если значение представимо в нем. Иначе - unsigned int, если представимо в нем. Иначе - long, если т.с., иначе - unsigned long. Для шестнадцатиричного и восьмеричного литерала тип является unsigned int, если литерал представим в нем, иначе - unsigned long. И еще гуча гемороя для неявных преобразований в арифметических операциях. Правда, нормальные компиляторы обычно выдают warning'и. Я поэтому и спрашивал про разрядность, т.к. если 16, -32768..+32767 то тип 60000 (0xEA60) - unsigned int. А вот тип 30000 - int, и 2 - тоже int. Поэтому тип 30000*2 тоже int и равен -5536 (0xEA60). То есть значение одно, а тип разный. В данном контексте это влияет на то, как будет выполняться сдвиг вправо - если это int, то старшие биты заполняются знаком, если unsigned - нулем. кстати, меня смущает строка: SPIDrvWrite(0x1B,(UINT16)((u32Timeout >>16) &0x000000FF) |0x000080FF); эквивалентно SPIDrvWrite(0x1B, 0x000080FF); ?