Thread: Using sscanf to parse/match an GPS (NMEA) string

  1. #1
    Registered User
    Join Date
    Mar 2011
    Posts
    278

    Using sscanf to parse/match an GPS (NMEA) string

    I've got some sample code that I'm trying to get working / understand.

    The sample code has a line:
    Code:
    if(sscanf(msg, "GPGGA,%f,%f,%c,%f,%c,%d,%d,%f,%f,%c,%f", &time, &latitude, &ns, &longitude, &ew, &lock, &sats, &hdop, &alt, &unit, &geoid) >= 1)
    The char array, msg[256], holds something like:
    Code:
    GPGGA,172814.0,3723.46587704,N,12202.26957864,W,2,6,1.2,18.893,M,-25.669,M,2.0,0031*4F"
    What I don't comprehend (even after looking at the online docs) is just how sscanf, used as above, works.

    If msg starts with a different string than GPGGA, will the sscanf stop?
    and based on docs, it seems it should return a '0' (for no matches), no?
    But if it returns a -1, what does that mean?

    (BTW, I am passing it the sample char array I provided, and I get returned '-1')

    Hope that was clear, and thanks.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,739
    > If msg starts with a different string than GPGGA, will the sscanf stop?
    Yes.
    Every character except % literally matches itself.

    The format character following a % will consume as much input as possible.
    So for example, attempting to parse "hello,world" with "%s,%s" is doomed to fail because the first %s will grab the whole input.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,352
    Quote Originally Posted by mike65535
    But if it returns a -1, what does that mean?
    Recall:
    Quote Originally Posted by C99 Clause 7.19.6.2 Paragraph 16
    The fscanf function returns the value of the macro EOF if an input failure occurs before any conversion. Otherwise, the function returns the number of input items assigned, which can be fewer than provided for, or even zero, in the event of an early matching failure.
    Clearly, the number of input items assigned cannot be a negative number, and as we know EOF is negative, you must be observing a return value of EOF. Therefore, it means that an input failure occurred before any conversion.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #4
    Registered User
    Join Date
    Mar 2011
    Posts
    278
    Thanks, both posts were quite helpful!

    Quote Originally Posted by laserlight View Post
    Recall:

    Clearly, the number of input items assigned cannot be a negative number, and as we know EOF is negative, you must be observing a return value of EOF. Therefore, it means that an input failure occurred before any conversion.
    OK, so... let me get this straight. The '-1' means I'm not really passing it a valid msg ?

  5. #5
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,739
    Anything other than 11 isn't a valid message.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  6. #6
    Registered User
    Join Date
    Mar 2011
    Posts
    278
    OK, I'm not getting a return of '-1' any more. So msg is valid but not a valid "msg" LOL.
    Thanks.

    But... I am getting a return of '0'.

    1) If msg has more fields in it than the format string in sscanf, that's OK, correct?
    2) If data is missing between the commas, is that OK?
    IOW, msg looks like GPGGA,,,,,,0,00,99.99,,,,,,*48

  7. #7
    Registered User
    Join Date
    Mar 2011
    Posts
    278
    If I test my sscanf with a test message
    Code:
    strcpy(msg,"GPGGA,,,,,,0,00,99.99,,,,,,*48");
    I get a return of 0

    A more complete test message works better -
    Code:
    strcpy(msg, "GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47");
    I get a return of 11

    Can you explain this to me?

    Thanks

  8. #8
    Registered User
    Join Date
    Jun 2015
    Posts
    1,643
    scanf doesn't support optional fields. It fails as soon as it hits the first comma while trying to read a float. You're better off tokenizing the string. Unfortunately (or not) you can't use strtok since it treats multiple separators in a row as one separator. But you can use strchr to look for commas.
    Code:
    #include <stdio.h>
    #include <stdlib.h>  // atoi, atof
    #include <string.h>  // strchr
    
    int main() {
        //char msg[] = "GPGGA,172814.0,3723.46587704,N,12202.26957864,"
        //             "W,2,6,1.2,18.893,M,-25.669,M,2.0,0031*4F";
        char msg[] = "GPGGA,,,,,,7,13,99.99,,,,,,*48";
    
        float time=0, latitude=0, longitude=0, hdop=0, alt=0, geoid=0;
        char ns='?', ew='?', unit='?';
        int lock=0, sats=0;
    
        char *p = strchr(msg, ',');
        time = atof(p+1); // if field is empty this encounters a comma and returns 0.0
    
        p = strchr(p+1, ',');
        latitude = atof(p+1);
    
        p = strchr(p+1, ',');
        ns = p[1] == ',' ? '?' : p[1];
    
        p = strchr(p+1, ',');
        longitude = atof(p+1);
    
        p = strchr(p+1, ',');
        ew = p[1] == ',' ? '?' : p[1];
    
        p = strchr(p+1, ',');
        lock = atoi(p+1);
    
        p = strchr(p+1, ',');
        sats = atoi(p+1);
    
        p = strchr(p+1, ',');
        hdop = atof(p+1);
    
        p = strchr(p+1, ',');
        alt = atof(p+1);
    
        p = strchr(p+1, ',');
        unit = p[1] == ',' ? '?' : p[1];
    
        p = strchr(p+1, ',');
        geoid = atof(p+1);
    
        printf("%f %f %c %f %c %d %d %f %f %c %f\n",
               time, latitude, ns, longitude, ew, lock,
               sats, hdop, alt, unit, geoid);
    
        return 0;
    }

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,739
    strsep(3) - Linux manual page is an alternative, but is less portable.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  10. #10
    Registered User
    Join Date
    Mar 2011
    Posts
    278
    Thanks laser salem and algor, this has been quite helpful. Now it's way more clear. I also greatly appreciate algor's code example to handle this better.

    As far as my code goes, I'm not building something for production so I'll just deal with the shortcomings of using sscanf (and its return code) with messages that may appear with all the blank fields.

    Cheers.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. parse string in C using sscanf
    By Keshav Gowtham in forum C Programming
    Replies: 4
    Last Post: 08-24-2015, 07:52 AM
  2. Checking input if no match parse as normall.
    By MaSSaSLaYeR in forum C Programming
    Replies: 5
    Last Post: 11-22-2011, 08:59 AM
  3. sscanf string match
    By ssharish2005 in forum C Programming
    Replies: 2
    Last Post: 01-25-2010, 10:27 PM
  4. Using sscanf to parse string
    By NuNn in forum C Programming
    Replies: 3
    Last Post: 02-19-2009, 06:20 PM
  5. sscanf does'nt parse a simple file correctly
    By seidel in forum C Programming
    Replies: 2
    Last Post: 02-12-2008, 07:15 AM

Tags for this Thread