I have to debug code and look into source code of Freescale USB stack (v4.0.3) because of my project.
In khci_kinetis.c::_usb_khci_atom_tr(), line 261, there is a statement I can not fully understand.
if (USB_EVENT_SET == _usb_event_wait_ticks(&khci_event, KHCI_EVENT_MASK, FALSE, 1) == USB_OK)
{
break;
}
#define USB_EVENT_SET 0x02
#define USB_OK 0x00
uint_16 _usb_event_wait_ticks(USB_EVENT_STRUCT_PTR, uint_32, uint_8, uint_16);
That statement means
if (0x02==var==0x00) break;
What is it anyway? I guess the judgement will be evaluated from left to right. If var equals to 0x02, then it is 0x01 as True. Otherwise it is 0x00 as false, then the truth value is compared to 0x00 to get second turth result.
Am I right? I still get confused why Freescale use such statement.
I double checked with v4.1.1, the latest release USB stack, it changes to
if ((USB_EVENT_SET == _usb_event_wait_ticks(&khci_event, KHCI_EVENT_MASK, FALSE, 1)) == USB_OK)
{
break;
}
It makes things much easier and safer. However, I doubt why Freescale can not use much simpler statements such as
if (USB_EVENT_SET == _usb_event_wait_ticks(&khci_event, KHCI_EVENT_MASK, FALSE, 1))
or
if (USB_EVENT_SET != usb_event_wait_ticks(&khci_event, KHCI_EVENT_MASK, FALSE, 1))
NOTE: The original source code is:
if ((USB_EVENT_SET == _usb_event_wait_ticks(&khci_event, KHCI_EVENT_MASK, FALSE, 1)) == USB_OK)
Then, the original question is not :
if(A == B == C)
But is:
if( (A == B) == C)
You can try out code snippets if you are not sure what they do here:
This is a demo of Gimpel's Lint program.
If you are doing embedded code you should be using Lint to make sure there are no lurking bugs.
Their Bug-of-the-Month is educational: Gimpel Software Bug of the Month
Here is an example, with deliberate bugs, you can copy into their demo analyzer:
/*lint -e438 Suppress 'unused' */
void main( void )
{
int A,B;
unsigned int C;
A = 0;
B = 1;
C = 2U;
if( A==B==C )
{
A = B = C = 3U;
}
if( A == C )
{
C = 4;
}
}
>The break will execute if, and only if, the three expressions have the same value.
This is not true.
Given A=0,B=0,C=0
A==B==C = (A==B) == C
A ==B = 1 (true)
1 == C (false)
The break will not execute.
Given A=1, B=0, C=0 the break will execute.
It will be evaluated:
1) tmpAB = (A==B), resulting in a value with BOOLEAN type [0, 1];
2) result = (tmpAB == C), which expect C with same type as tmpAB: BOOLEAN.
The result will be TRUE (and break) when (A==B && C==1) || (A!=B && C==0), FALSE otherwise.
But for the values and expressions involved in the statements it seems to me more like a bug than a rare combination of NOT/XOR operations (which makes no sense as C is constant in the expression: USB_OK is 0).
As USB_OK is defined as zero (same as FALSE), the expression is simply equivalent to:
if (USB_EVENT_SET != _usb_event_wait_ticks(&khci_event, KHCI_EVENT_MASK, FALSE, 1))
{
break;
}
Many thanks to Bob Paddock for mentioning the tool, this kind of tools come very handy for bringing light into obscure code.
Yes Jim, that's correct, the existance or not of one C type called "BOOLEAN"/"bool"/"boolean"/"_Bool" is compiler implementation specific (some compilers for the embedded world already define and implement the boolean type, with variations in the name and decorators). Most compilers do not follow the standards in a strict manner (C99, C11, C89, C90, and so on).
BOOLEAN in this case was just a concept, also a compile time type checking rule (in some compilers and tools, as C is too relaxed), that at the end will always be processor and compiler dependant.
In most implementations the result of logical operators/operations is assumed to be one integer with value range from 0-to-1, only one bit out of the native word is used for simplifying the native code so instructions like bitwise AND/OR/XOR/CMP/etc. can be directly used, and in some other implementations it's simply tested as Zero/Not_Zero (any value but zero is TRUE) for taking advantage of dedicated processor core machine instructions/microcode.