Previous Entry Share Next Entry
2016-01

препроцессор буэээ (проблема решена)


#define R_PU_33 17890UL
#define R_PD_33 988UL
#define ADC_V_REF 2560UL

#define MV_TO_ADC(MV,  R_PU, R_PD) (((MV)*(unsigned long)1024UL*(R_PD))/((ADC_V_REF)*((R_PU)+(R_PD))))

int _tmain(int argc, _TCHAR* argv[])
{
    unsigned long i=0;
    i=MV_TO_ADC(33000UL, R_PU_33, R_PD_33);
    printf("%l", i);
    return 0;
}

Этот код печатает “68” из-за integer overflow в числителе, несмотря на то, что везде где можно воткнуты unsigned long, и правильный ответ 690.

Что делать? Вручную раскрывать макросы не хочется, их подобных много. Проверено на msvc, gcc и avr-gcc (ATMEL).


  • 1
sashman January 3rd, 2010
Что интересно (и очевидно),
#define MV_TO_ADC(MV, R_PU, R_PD) (((((MV)*1024)/(ADC_V_REF))*(R_PD))/((R_PU)+(R_PD)))
работает нормально.

т.е. в cc не выполняются базовые законы математики. И никаких ворнингов, что особо противно.

Тысячи желчи на разработчиков.

zeux January 4th, 2010
На всякий случай, отмечаю.

а. препроцессор не при чем, он ничего не вычисляет в данном случае, он просто подставляет текст. Вычисляет компилятор, либо процессор (если компилятор не схлопнул выражение в константу).
б. Базовые законы математики вообще не выполняются в целочисленной арифметике, с учетом truncate при делении и under/overflow :)

sashman January 4th, 2010
а. вот она, протечка абстракций.
мне всё равно, кто будет считать, препроцессор, компилятор или вообще линкер, лишь бы не таргет процессор, и не программист с калькулятором.
б. втихаря же не выполняются.

faceted_jacinth January 3rd, 2010
Проверил на msvc 2008, в обоих режимах (х64 и х32).

Во-первых, он тебе выдаёт варнинг.

Во-вторых, запомни: типы long, unsigned long, и соответствующие константы использовать нельзя, вместо них следует использовать long long, unsigned long long и LL/ULL суффиксы, а ещё лучше - подключить types.h или как там её, где объявлены int64_t сотоварищи. Ну или накрайняк самому себе написать. Я к тому, что так всё работает правильно вощемта.

faceted_jacinth January 3rd, 2010
А всё от того, что размер лонга ваще нигде не определён и флуктуирует в зависимости от желаний левой задней ноги разработчиков компилятора. Причём у мсвц по ходу 8, но для констант -- 4.

Алсо, подумай над тем, чтобы всё-таки заменять эту порнуху на static const и inline функции потихоньку!

wizzard0 January 3rd, 2010
Мопед, в принципе, не мой, впрочем, все равно спасибо. Автор мопеда, думаю, комментарии тоже уже прочитал.

sashman January 4th, 2010
про long long спасибо, благо avr-gcc хавает нотацию типа 33000ULL



какбэ речь про 8-битные микроконтроллеры о сотнях байт ОЗУ и килобайтах флеша под код, так что порнуха иногда необходима.

кстати, если параметры макроса переменные - имеем инлайн-вычисление. Константы - константу.
в случае же заворачивания в функцию - набоум компилятора, заоптимизирует - не заоптимизирует.

faceted_jacinth January 4th, 2010
Ну, я не знаю насчёт GCC, а вот какому-нибудь Кейловскому компилятору я бы скорее доверил самому решать насчёт необходимости инлайна inline функции и прочего. Он сцуко умный был! Ну и кстати если уж жалко флеша под код, то инлайнить довольно часто наоборот не нужно ни за что, а вот на способность компилятора узреть одинаковую структуру после раскрытия макросов и вынести её в функцию я бы надеяться не стал, теоретически он это умеет, практически - как повезёт.

sashman January 4th, 2010
1. Keil не выпускает компилятор под эту платформу. Выбор есть между gcc, IAR (переход gcc ↔ IAR сопровождается переписыванием архитектурно-зависимого кода, т.к. разумеется либы у них разные). И православным ассемблеромъ.

2. Макрос/функция - на самом деле, не столь принципиально. И в любом случае будет переписано для хранение констант в ээпроме.

zeux January 4th, 2010
Размер long строго говоря конечно не определен, однако почти везде по факту 4 байта, насколько я знаю. В том числе и в MSVC, и в 32-битном и в 64-битном. Так не бывает, чтобы тип был 8 байт, но его константы были 32-битными :)

faceted_jacinth January 4th, 2010
А, ну да, конечно, этом меня заглючило что-то.

В 64битном gcc лонг всё-таки восьмибайтный, но под рукой его нет, чтобы посмотреть, как там с константами!

wizzard0 January 3rd, 2010
А какие галочки, кстати, нужно включить, чтоб получить ворнинг? У меня молчит как партизан, и на 32 и на 64.

faceted_jacinth January 4th, 2010
Вот уж не знаю! Ворнинг вот: http://msdn.microsoft.com/en-us/library/4kze989h(VS.80).aspx, я традиционно компилю вообще с /W4

  • 1
?

Log in

No account? Create an account