Неожиданное поведение ++myCount

Я новичок в Arduino и C. Такое поведение не соответствует моим ожиданиям:

Serial.begin(9600);
while ( ! Serial );

int myCount = 0;

for (int i=0; i<10; i++) {
    myCount = min( ++myCount, 8 );
    Serial.print( myCount );
    Serial.print( "  " );
}

Я ожидал:

1  2  3  4  5  6  7  8  8  8

Но я понимаю:

2  4  6  8  8  8  8  8  8  8

Почему мой код считает на 2?

, 👍3

Обсуждение

Из-за особенностей реализации функции min() избегайте использования других функций внутри скобок, это может привести к неверным результатам: https://www.arduino.cc/reference/en/language/functions/math/min/, @VE7JRO

если min — это *макрос*, например #define min(a,b) ((a)<(b)?(a):(b)), подумайте, что произойдет, если вы *расширите* min( ++) myCount, 8 ) .... вы получаете ((++myCount)<(8)?(++myCount):(8)) - однако я не думал, что это макрос, так что это странно, @Jaromanda X


1 ответ


5

Jaromanda X действительно прав: min() определен в строке 92 Arduino.h, таким образом:

#define min(a,b) ((a)<(b)?(a):(b))

Поэтому, когда ++mycount заменяется на a, он фактически заменяется дважды, как в ( a)<(b) и (a):(b), что приводит к увеличению на 2 каждый раз, когда min(+ +mycount,8) выполняется.

Как упоминает VE7JRO, как это определено таким образом, ссылка для <code>min(x,y)</code> утверждает:

Предупреждение

Из-за особенностей реализации функции min() избегайте использования другие функции внутри скобок, это может привести к неверным результатам

min(a++, 100);   // избегайте этого - дает неправильные результаты

min(a, 100);
a++;            // используйте это вместо этого - оставьте остальную математику вне функции

Как указано во втором примере, продолжайте увеличивать любой вне макроса min().

В качестве альтернативы, я думаю, вы могли бы использовать функцию inline для решения этой проблемы:

#undef min
inline int min(int a,int b) {return ((a)<(b)?(a):(b)); }

Поскольку inline обеспечивает настоящий вызов функции (с параметрами), он позволяет избежать использования макросов и подстановок, что приводит к возникновению проблемы, с которой вы столкнулись.

>

inline — во многих случаях гораздо лучший (более безопасный) способ реализовать функциональность, предоставляемую макросами. Дополнительную информацию см. в разделе Встроенные функции в C++ или в справочнике по C++.

,

Преимущество использования макроса в том, что он не зависит от типа. Вы можете использовать его с float, double, char, int, long, подписанным или беззнаковым, и ему все равно., @Majenko

esp8266 имеет min() в качестве функции шаблона., @Juraj