3

I'm new to Arduino and C. This behavior is not what I'd expect:

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

int myCount = 0;

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

I would expect:

1  2  3  4  5  6  7  8  8  8

But I get:

2  4  6  8  8  8  8  8  8  8

Why is my code counting by 2?

Greenonline
  • 2,938
  • 7
  • 32
  • 48
StormDog
  • 31
  • 2
  • Because of the way the min() function is implemented, avoid using other functions inside the brackets, it may lead to incorrect results: https://www.arduino.cc/reference/en/language/functions/math/min/ – VE7JRO Dec 07 '18 at 07:11
  • 2
    if min is a macro such as #define min(a,b) ((a)<(b)?(a):(b)) think about what happens when you expand min( ++myCount, 8 ) .... you get ((++myCount)<(8)?(++myCount):(8)) - however, I didn't think it was a macro, so that's odd – Jaromanda X Dec 07 '18 at 08:23

1 Answers1

5

Jaromanda X is indeed correct - min() is defined on line 92 of Arduino.h, thusly:

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

Therefore when the ++mycount is substituted for the a, it is in fact substituted twice, in both the (a)<(b) and the (a):(b), leading to the increment by 2, each time min(++mycount,8) is executed.

As VE7JRO mentions, as it is defined in this way, the reference for min(x,y) states:

Warning

Because of the way the min() function is implemented, avoid using other functions inside the brackets, it may lead to incorrect results

min(a++, 100);   // avoid this - yields incorrect results

min(a, 100);
a++;            // use this instead - keep other math outside the function

As the second example states, keep any incrementing outside of the min() macro.

Alternatively, I think that you could use the inline function to workaround this issue:

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

Because inline provides a real function call (with parameters) it avoids the use of macros and substitution, which gives rise to the issue that you encountered.

inline is a much better (safer) way to implement the functionality provided by macros, in many cases. For more information, see Inline functions in C++ or read a C++ reference.

Greenonline
  • 2,938
  • 7
  • 32
  • 48
  • 2
    The advantage of using a macro is it is type agnostic. You can use it with float, double, char, int, long, signed or unsigned, and it doesn't care. – Majenko Dec 07 '18 at 15:21
  • 2
    esp8266 has min() as template function. – Juraj Dec 07 '18 at 17:26