Welcome to all that is bad, (or good if you understand whats going on), about C/C++ and most other languages.
This entire thread has nothing to do with WebbotLib or rprintf - its ALL about how C works.
The WebbotLib 'rprintf' command is identical to the standard C 'printf' routine in that it takes a variable number of parameters. The first parameter is the 'format string' showing how to display the answer. The remaining parameters are the values to be used in the format string.
The format string can contain things like:-
%s - to display a string
%d - to show a signed 16 bit (int16_t) number
%u - to show an unsigned 16 bit (uint16_t) number
%ld - to show a signed 32 bit (int32_t) number
Given the format strings you have used then the additional parameters should contain data which matches the data type from the format string.
You know this. The C language syntax document knows this. But unfortunately all C compilers have no idea that this is the case. As far as the compiler is concerned the format string is just that - its just a string. So the compiler has no way to check the datatypes in the format string against the other parameters which represent the values to be substituted.
As a simple example - the following is totally allowed by the compiler:
int16_t num = 65;
rprintf("Text =%s\n", num);
This will compile without any errors and you may expect it to output 'Text =65' but you would be very wrong.
It will output complete junk. The format string contains a %s meaning it should be replaced by the string given in the arguments. But the only other argument is 'num' which is an integer number and not a string. Since 65 is the ASCII value for 'A' then it will probably, if you are lucky, show 'Text =A' but, if you are unlucky' then this may be proceeded by all sorts of gubbins.
So lets take a look at one of admins examples:-
uint32_t b = 17897;
int16_T a = -599;
rprintf("%d %d %ld\n",a,b,a*(b/1000000));
The format string shows that it expects:
- an int16_t
- another int16_t
- an int32_t
But the actual parameters passed in are:
- 'a' an int16_t
- 'b' an uint32_t
- 'a*(b/1000000)' hard to say but since every element is an integer - the largest being a 32 bit number - then will probably be an int32_t
The result is that it prints out this data:
-599 17897 4
which Admin 'thinks' is wrong. Lets go through it by comparing the info shown above for what the 'format string' has been asked to do vs the actual parameter it has been passed to use.
1. Format string has '%d' ie an int16_t and it has been passed 'a' which is an int16_t and so outputs the correct answers '-599'
2. Format string has '%d' ie an int16_t and it has been passed 'b' which is an uint32_t. So now it will start outputing the wrong data.
3. Since the previous entry has been messed up then all remaining parameters will also be messed up.
Thats why the third value comes out as 4 rather than 0 - its messed up because of the mismatch on the previous values format string vs the data its been given.
So one way to fix it is force the parameters to match the types specified in the format string by using a cast. ie
rprintf("%d %d %ld\n",(int16_t)a, (int16_t)b, (int32_t)(a* (b/1000000) ) );
This will now output the last value as '0' rather than the erroneous '4'.
Admin tried to do this by having this as a seperate line of code which also outputs '0':-
rprintfFloat(8,a*(b/1000000));
The next question admin has is why does that last value come out as 0?
Well a=-599 and b=17897.
These are both whole numbers (integers).
The first step is (b/1000000) where b is an integer and 1000000 is an integer so the result (0.017897) as an integer is 0. Multiply by 'a' and the answer is still 0.
Since the rprintfFloat function expects a 'float' value then it will convert the value to a 'float' before printing. ie it converts the integer value '0' to the float value '0.000000'.
What about
rprintfFloat(8,(a*b)/1000000);
a * b = -10,720,303
div by 1000000 = -10
Converted to a float is -10.00000
So this will output -10.00000
So now we are getting closer but we are still seeing a whole number as the answer.
The 'fix' is to let the C compiler know that we are using floating point numbers inside the formula. ie
rprintfFloat(8,(a*b)/1000000.0);
By adding the '.0' on the end then we are specifying a floating point number and not an integer
or
rprintfFloat(8,(a*b)/1000000f);
By adding the 'f' at the end then we are saying its a floating point number.
So now we have (int * int) / (float) and so the answer will be a float rather than an integer
a * b = -10,720,303
div by 1000000.0 = -10.720303
Converted to a float is -10.720303
So this will output -10.720303
--- Update --
Admin has just said how
rprintf("%d %d\n",a,b);
rprintf("%ld",a*(b/1000000));
Seems to work but doesn't know why.
Well the reason is that he has split the rprintf into two - choosing the place where his format string was messing everything up.
Hopefully the discussion above will describe why it now works (but is actually still bad code as its fixed the output but not the problem)
