adnega 11 16 декабря, 2012 Опубликовано 16 декабря, 2012 · Жалоба Имеем gcc, пишем на C. Задача: нужно написать некоторый макрос TICK(x), который бы при каждом вызове увеличивал переменную x на константу TO_TICK, но с учетом переполнения. Т.е. в случае если добавление TO_TICK вызовет переполнение, переменную x не изменять. Тип переменной x может быть любой целый (в том числе битовое поле). Вариант 1: #define TICK(x) do{if((x + TO_TICK) > x) x += TO_TICK;}while(0) не помогает, в случае знакового x и беззнакового TO_TICK. Видимо, (x + TO_TICK) считается беззнаковым и сравнивается с беззнаковым x. Вариант 2: #define TICK2(x) do{typedef typeof(x) _tx; _tx _x = x; _x += TO_TICK; if(_x > x) x = _x;}while(0) в принципе устраивает, но не работает с битовыми полями. Параллельно узнал, что char без указания знаковости в "gcc version 4.8.0 20121121 (experimental) (Klen's GNU package (KGP) for ARM/elf platform)" является unsigned, хотя везде указывается диапазон char от -128 до 127. В "gcc версия 4.4.3 (GCC)" под Linux char знаковый. Где нужно читать о типах данных C/GCC и приведении типов в арифметических операциях и операциях сравнения? Кстати, при различных уровнях оптимизации результат тоже получаю различный. Хочется большей строгости... Спасет ли переход на C++/GCC ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_Pasha 0 16 декабря, 2012 Опубликовано 16 декабря, 2012 (изменено) · Жалоба #define TICK(x) do{ unsigned char a = x+TO_TICK; if(a > TO_TICK) x=a;}while(0); и вообще, какого икса дефайнить? static inline Tick(unsigned char *x) { unsigned char a = *x+TO_TICK; if(a > TO_TICK) *x=a; } Изменено 16 декабря, 2012 пользователем _Pasha Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
adnega 11 16 декабря, 2012 Опубликовано 16 декабря, 2012 · Жалоба и вообще, какого икса дефайнить? Чтобы работало для разных типов на автомате. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_Pasha 0 16 декабря, 2012 Опубликовано 16 декабря, 2012 (изменено) · Жалоба Чтобы работало для разных типов на автомате. Во! А теперь еще более интересный вопрос: у Вас "тикающий тип" - это одна сущность или много? Вернее, почему нельзя создать тип нужной размерности, скажем typedef unsigned int tick_t Если на то есть причины, расскажите, плз, очень интересно. Изменено 16 декабря, 2012 пользователем _Pasha Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
adnega 11 16 декабря, 2012 Опубликовано 16 декабря, 2012 · Жалоба Во! А теперь еще более интересный вопрос: у Вас "тикающий тип" - это одна сущность или много? Вернее, почему нельзя создать тип нужной размерности, скажем typedef unsigned int tick_t Если на то есть причины, расскажите, плз, очень интересно. А то! Раньше было много, сейчас, видимо, придется переходить на одну. В целях экономии памяти использую различную разрядность "тикающих типов", в идеале вплоть до битовых полей. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_Pasha 0 16 декабря, 2012 Опубликовано 16 декабря, 2012 (изменено) · Жалоба А то! Раньше было много, сейчас, видимо, придется переходить на одну. В целях экономии памяти использую различную разрядность "тикающих типов", в идеале вплоть до битовых полей. В таком случае (мсм) - проще функцию инлайновую завести, в аргументе const tick_t Эффектов побочных от битовых полей не ожидается. При желании наплевать на контроль типов - обернуть функцию в дефайн. Вроде чуть больше строк, но просто и работать должно. Но не проверял :laughing: PS inline tick_t Tick(const tick_t tikable){} Изменено 16 декабря, 2012 пользователем _Pasha Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
adnega 11 16 декабря, 2012 Опубликовано 16 декабря, 2012 · Жалоба Вариант 2: #define TICK2(x) do{typedef typeof(x) _tx; _tx _x = x; _x += TO_TICK; if(_x > x) x = _x;}while(0) в принципе устраивает, но не работает с битовыми полями. Не работает при вызове TICK2 в SysTick при оптимизации Os, хотя при использовании во вложенных функциях, вызываемых из SysTick - работает. Блин... Сделаю выделенный "тикающий тип" и заведу функцию для контроля передаваемого типа. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Артём__ 0 16 декабря, 2012 Опубликовано 16 декабря, 2012 · Жалоба Сделаю выделенный "тикающий тип" и заведу функцию для контроля передаваемого типа. Почему перегрузку функций не использовать? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
adnega 11 16 декабря, 2012 Опубликовано 16 декабря, 2012 · Жалоба Не работает при вызове TICK2 в SysTick при оптимизации Os, хотя при использовании во вложенных функциях, вызываемых из SysTick - работает. Блин... Сделаю выделенный "тикающий тип" и заведу функцию для контроля передаваемого типа. Пока сделаю так: typedef volatile unsigned long tTIMER; void __inline tick(tTIMER *t) { tTIMER temp; temp = *t; temp += TO_TICK; if(temp > (*t)) *t = temp; } tTIMER test_ttimer; // тестовая переменная tick(&test_ttimer); // вызов функции тика Причем "тикать" строго из одного потока. Читать таймер из любого множества потоков. Почему перегрузку функций не использовать? Потому что чистый C. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Артём__ 0 16 декабря, 2012 Опубликовано 16 декабря, 2012 · Жалоба Потому что чистый C. Зачем эта "чистота"? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_Pasha 0 16 декабря, 2012 Опубликовано 16 декабря, 2012 · Жалоба Попутно еще замечание, что параметр функции const утаптывается оптимизатором лучше, и если пользоваться tTIMER __inline tick(const tTIMER tmr) { tTIMER temp= tmr+TO_TICK; return (temp > TO_TICK)? temp:tmr; } tTIMER test_ttimer; // тестовая переменная test_ttimer = tick(test_ttimer); может быть лучше. Вот сравните без volatile, если интересно, конечно :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
polyname 0 17 декабря, 2012 Опубликовано 17 декабря, 2012 (изменено) · Жалоба может лучше сравнивать с разностью ? #define ADD_LIMIT(x,dx,max) x = ((x) < ((max) - (dx))) ? ((x) + (dx)) : (max) Изменено 17 декабря, 2012 пользователем polyname Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
andrew_b 16 17 декабря, 2012 Опубликовано 17 декабря, 2012 · Жалоба Параллельно узнал, что char без указания знаковости в "gcc version 4.8.0 20121121 (experimental) (Klen's GNU package (KGP) for ARM/elf platform)" является unsigned, хотя везде указывается диапазон char от -128 до 127. В "gcc версия 4.4.3 (GCC)" под Linux char знаковый. Где нужно читать о типах данных C/GCC и приведении типов в арифметических операциях и операциях сравнения? Читать нужно стандарт языка Си. 15 The three types char, signed char, and unsigned char are collectively called the character types. The implementation shall define char to have the same range, representation, and behavior as either signed char or unsigned char. Иными словами, знаковость типа char зависит от реализации. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ARV 1 17 декабря, 2012 Опубликовано 17 декабря, 2012 · Жалоба #define TICK(x) x = ((x) + TO_TICK) < (x) ? (x) : ((x) + TO_TICK) может так? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 17 декабря, 2012 Опубликовано 17 декабря, 2012 · Жалоба Задача: нужно написать некоторый макрос TICK(x), который бы при каждом вызове увеличивал переменную x на константу TO_TICK, но с учетом переполнения. Т.е. в случае если добавление TO_TICK вызовет переполнение, переменную x не изменять. А вам точно нужно это? Может, лучше - с ограничением? #define VAR_INC(x, step, max) x = ((x + step)>max)? max : (x + step) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться