Search code examples
cscanfpicidentifiermplab

C sscanf not capturing the second argument


Using MPLAB to code for PIC16 in C using the XC8 compiler.

I am trying to capture some baud rate settings from a string, for example "115200,8,N,1". For the purpose of my application, I have opted to use an enum for parity (N,O,E becomes 0,1,2).

I have the following code:

#include <stdint.h>

int main(void)
{
    uint32_t baudrate;
    uint8_t databits, parity, stopbits;

    char *input = "115200,8,0,1";

    sscanf(input, "%lu,%u,%u,%u", &baudrate, &databits, &parity, &stopbits); 
    printf("%lu - %u - %u - %u\n", baudrate, databits, parity, stopbits);

    return 0;
}

And I would expect the following output:

>> 115200 - 8 - 0 - 1

However, I get:

>> 115200 - 0 - 0 - 1

What am I doing wrong, as it always appears that the second capture returns 0. I assume that I am using the wrong identifiers, but which ones should be used?


Solution

  • %u tells sscanf to match an optionally signed decimal integer in the input string, to convert its value to unsigned int, and to store the result in an unsigned int pointed to by the corresponding argument.

    &databits does not point to an unsigned int. As a consequence, the behavior of the program is not defined by the C standard.

    Similarly, %u for &parity and %u for &stopbits are wrong, and %lu for &baudrate may or may not be wrong, depending on particulars of the C implementation.

    Correct conversion specifier characters are defined by macros in the <inttypes.h> header and may be used like this:

    #include <inttypes.h>
    #include <stdio.h>
    #include <stdint.h>
    
    
    int main(void)
    {
        uint32_t baudrate;
        uint8_t databits, parity, stopbits;
    
        char *input = "115200,8,0,1";
    
        sscanf(input, "%" SCNu32 ",%" SCNu8 ",%" SCNu8 ",%" SCNu8,
            &baudrate, &databits, &parity, &stopbits); 
        printf("%" PRIu32 " - %" PRIu8 " - %" PRIu8 " - %" PRIu8 "\n",
            baudrate, databits, parity, stopbits);
    
        return 0;
    }
    

    SCN starts a macro for scanf conversion characters, and then u is for an unsigned integer type, and it is followed by the number of bits. PRI starts a similar macro for printf conversions. These macros will be replaced by quoted strings, and the consecutive quoted strings in the code above will be merged into a single string.

    For example, "%" SCNu32 ",%" SCNu8 ",%" SCNu8 ",%" SCNu8 may end up equivalent to %u,%hhu,%hhu,%hhu.

    End your printed lines with \n. This works better with C defaults regarding buffer and with shell behavior.

    Use return 0; or return EXIT_SUCCESS; (defined in <stdlib.h>) in main to exit a successful program execution. You can also let control flow to the end of main to exit a successful program execution. Use return EXIT_FAILURE; to indicate a failure. You can use return 1; in specific environments, but you should be aware it is not portable.