Search code examples
printfavriotcontiki

Unexpected behavior in printf() function in Contiki


i was trying to test some timers in contikiOS, i used printf() to output the value of a variable but the printed value changed acording to how i printed the message.

What do i mean?, well i print two variables, RTIMER_SECOND is a long unsigned int and CLOCK_SECOND is an integer. The variations bellow are what i tried and the output is bellow that code:

    printf("1->RTIMER_SECOND=%lu CLOCK_SECOND=%d\n", RTIMER_SECOND, CLOCK_SECOND);
    printf("2->RTIMER_SECOND=%d CLOCK_SECOND=%d\n\n", RTIMER_SECOND, CLOCK_SECOND);

    printf("3->CLOCK_SECOND=%d RTIMER_SECOND=%lu\n", CLOCK_SECOND,RTIMER_SECOND);
    printf("4->CLOCK_SECOND=%d RTIMER_SECOND=%d\n\n", CLOCK_SECOND,RTIMER_SECOND);

    printf("Ticks per second: %lu\n", RTIMER_SECOND);
    printf("second per second: %d\n", CLOCK_SECOND);

The output is this:

1->RTIMER_SECOND=15625 CLOCK_SECOND=128

2->RTIMER_SECOND=15625 CLOCK_SECOND=0

3->CLOCK_SECOND=128 RTIMER_SECOND=15625

4->CLOCK_SECOND=128 RTIMER_SECOND=15625

Ticks per second: 15625

second per second: 128

My question is this why does the 0 appear in the 2nd print? is the undefined behaviour when printing the %d instead of %lu of the RTIMER_SECOND affecting the next variable? PS: the 4th is the reverse of the 2nd and the value of the CLOCK_SECOND is not 0 there.


Solution

  • printf() will be implemented by the OS. I don't know the details of the implementation.

    My guess is that the variables get passed to printf() as a sequence of bytes on the stack. The specifier string tells the function how many bytes to consume when printing the output.

    A long unsigned integer is 4 bytes, probably in little-endian order. Since 15625 is less than 2^16, then last two bytes of RTIMER_SECOND are both 0. When the string tells the function to only printf 2 bytes for RTIMER_SECOND, the next two 0 bytes are interpreted as the two bytes of CLOCK_SECOND.

    To test this hypothesis, try passing in a value for RTIMER_SECOND that takes more than 2 bytes, i.e., more than 65536. In that case, the 4th line will be messed up, too.