View previous topic :: View next topic |
Author |
Message |
gribas
Joined: 21 Feb 2008 Posts: 21
|
The insidious abs() function |
Posted: Tue Aug 14, 2012 7:39 am |
|
|
Hi,
Code: |
void main() {
int8 a,b,delta;
a = 1;
b = 2;
delta = abs(a-b);
printf("Delta abs(1-2) = %u \r\n",delta);
}
|
The result of course is not 1, but somehow I think it should be. I could not find the abs() function prototype inside the header files but from the help it gave me the impression that the parameter was treated as a signed value. The code below works.
Code: |
int8 my_abs(signed int8 value) {
return abs(value);
}
void main() {
int8 a,b,delta;
a = 1;
b = 2;
delta = my_abs(a-b);
printf("Delta my_abs(1-2) = %u \r\n",delta);
}
|
Regards, |
|
|
sseidman
Joined: 14 Mar 2005 Posts: 159
|
|
Posted: Tue Aug 14, 2012 7:55 am |
|
|
Try typecasting your operation inside the abs function. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Tue Aug 14, 2012 8:14 am |
|
|
1-2 (unsigned int8 arithmetic) gives binary 11111111.
at sseidman has said, cast one of more of the values to signed before the subtraction.
delta=abs((signed)a-b);
ABS is just a macro, not a function.
Basically
#define abs(x) (x<0)?-x:x
if you call it with two unsigned values it does it's maths with their type, and signe they can never be <0, returns the overflowed result....
Best Wishes |
|
|
gribas
Joined: 21 Feb 2008 Posts: 21
|
|
Posted: Tue Aug 14, 2012 8:43 am |
|
|
Hi,
I don't see how the value is treated as signed inside the function abs(). If that was the case it should work like my_abs() does. From my perspective I'm feeding the abs() function with the (one byte) value 0xFF. This value can be read as 255 or -1.
My point is that the abs() function should always treat its parameter as a signed parameter. I fail to see a situation where one would intentionally call abs() with an unsigned value.
Is it straightforward to you that the correct way to use the abs() should always be abs((signed)(x))?
Regards, |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Tue Aug 14, 2012 9:12 am |
|
|
The point is that it is _not a function_. Very key thing to understand. It is just a macro.
A function causes automatic type casting to it's defined type(s). A macro does _nothing_. This is why abs will work with any variable type (float, long, integer, etc. etc.), but whether it has any _meaning_ is dependant on the types of the variables.
Your 'wrapper function', automatically casts the variables to 'signed', so they start working. Without this, two unsigned values, no casting, so result<0, can never be 'true', so abs does not work.
The same is true of abs in most C's, _but_ in most C's, the default integer type is 'signed', so by default it works.
Best Wishes |
|
|
sseidman
Joined: 14 Mar 2005 Posts: 159
|
|
Posted: Tue Aug 14, 2012 9:30 am |
|
|
gribas wrote: |
My point is that the abs() function should always treat its parameter as a signed parameter. I fail to see a situation where one would intentionally call abs() with an unsigned value. |
My experience is that c compilers do exactly what you ask them to do without stopping to make sure it makes sense. You can make mistakes either way with abs(). The way you want it to behave will create bad results when the MSB is 1 for one of your operands.
FWIW, some of my most frequent errors involve data types and casting, and they tend to be hard to debug for me. It's taught me to be real careful about specifically casting when I have any questions. I suppose I could also just learn the rules about type conversions like the back of my hand, but try as I might, I often mess that up. |
|
|
gribas
Joined: 21 Feb 2008 Posts: 21
|
|
Posted: Tue Aug 14, 2012 10:04 am |
|
|
Hi,
Thanks a lot for your remarks. Ttelmah, I could not find the original ccs macro definition so I modified your's a little:
Code: |
#define abs2(x) (((signed)(x)) <0)?-(x):(x)
void main() {
int8 a,b;
a = 1;
b = 2;
printf("abs2(1-2) = %u \r\n",abs2(a-b));
}
|
It works, but I'll keep using the "abs((signed)a-b)" version as a reminder to always check the data types. =)
Regards, |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Tue Aug 14, 2012 3:45 pm |
|
|
Quote: | ABS is just a macro, not a function. |
Sounds plausible at first sight. But apparently it isn't defined as a macro anywhere in CCS include files. It
seems to be a built-in function. Or did I miss something?
K&R 2nd edition says it's an integer function with integer argument that belongs to stdlib. Consequently many
compilers implement it with an implicit typecast to int, e.g. Borland C or MSVC. Thus the expectation in the
original post isn't far fetched. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Wed Aug 15, 2012 1:20 am |
|
|
Two things:
Remember that in CCS C, an int is unsigned. This then leads to the rest of the behaviour, and the 'expectation' being wrong, whether it is a function, or a macro. This is the 'key thing to remember'.
However If you look in the existing include files, you will find labs, and fabs, both being #defined to just use abs. This will only work, if it is a macro. In CCS, it is I believe, an implicit macro (one defined inside the compiler, rather than in the includes).
Best Wishes |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Wed Aug 15, 2012 2:59 am |
|
|
Quote: | Remember that in CCS C, an int is unsigned. This then leads to the rest of the behaviour. |
Yes, if we assume that the C stdlib integer function has been implemented without much thinking.
By the way, the abs() behaviour is identical (like a macro) in PCD that has a signed integer type.
Personally, I don't have much expectations about the implementation of the C standard in CCS C. I just meaned to mention that the OP's expectation has some reasoning.
I agree to your consideration about labs(), although I don't know how an implicite macro in CCS C looks like. I imagine, that it's more powerful than a dumb preprocessor macro and can e.g. implement a typecast to different signed types. |
|
|
|