Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

sscanf crashes trying to read multiple 8-bit char numbers in a row

Status
Not open for further replies.

Drugo

Junior Member level 2
Joined
Feb 23, 2011
Messages
20
Helped
1
Reputation
2
Reaction score
1
Trophy points
1,283
Activity points
1,537
I'm using a Microchip C30 compiler on dsPIC33F family and struggling A LOT with sscanf() function. Please please please help me because my project is getting stuck for this little detail. I really hope that someone can help me, I haven't found anything on internet and I spent the last 2 days on this issue. Thanks a lot in advance

THE TASK

I have to read different types of numbers from a string (unsigned int, float, char and unsigned char).

THE ISSUES :oops:

I have problems reading numeric char and unsigned char (i.e. 8 bit numbers, not ASCII characters), but not the other ones. With problem I mean that sscanf() fails (crashes) during its execution without returning any numeric value. In particular the problems come when I try to read more than one char (or unsigned char) in a row. As a char conversion specifier I use %hhd, but I tried - at least I think - with all the possible combinations. For unsigned char I used %hhu.
In order to understand better please look at this examples with just float and char. Float are read correctly, char just in case A) with one char parameter.

A) JUST ONE CHAR HAS TO BE READ: it works correctly :grin: :lol: :p


Code C - [expand]
1
2
3
4
5
6
7
8
// 99 init values just for debugging resons
char string[] = "test1 12,1.525,2.789";
char theChar1 = 99;
float theFloat1;
float theFloat2;
int retVal = 99;
 
retVal = sscanf(&string[6],"%f,%f,%hhd",&theFloat1, &theFloat2, &theChar1);





B) TWO CHARS HAVE TO BE READ: it doesn't work, sscanf() does not complete its execution and doesn't provide a return value :-(


Code C - [expand]
1
2
3
4
5
6
7
8
9
// 99 init values just for debugging resons
char string[] = "test1 12,1.525,2.789";
char theChar1 = 99; 
char theChar2 = 99;
float theFloat1;
float theFloat2;
int retVal = 99;
 
retVal = sscanf(&string[6],"%f,%f,%hhd,%hhd",&theFloat1, &theFloat2, &theChar1, &theChar2);


C) THREE CHARS HAVE TO BE READ: it doesn't work, sscanf() does not complete its execution and doesn't provide a return value :-x


Code C - [expand]
1
2
3
4
5
6
7
8
9
// 99 init values just for debugging resons
char string[] = "test1 12,1.525,2.789";
char theChar1 = 99; 
char theChar2 = 99;
float theFloat1;
float theFloat2;
int retVal = 99;
 
retVal = sscanf(&string[6],"%f,%f,%hhd,%hhd,%hhd",&theFloat1, &theFloat2, &theChar1, &theChar2, &theChar3);


THANKS SO MUCH FOR YOUR HELP!!!
 
Last edited by a moderator:

@kam1787: as string is of type char[], string[6] is of type char. sscanf's first parameter is a char*, so you have to take the address of the char. He's just trying to offset the input into the buffer.

@drogu: for the third example, theChar3 doesn't appear to be declared. Is this just a problem with the post?

I'm a little curious what you think should happen? Your input string is "test1 12,1.525,2.789", and with the offset to sscanf that you're giving (with the &string[6] business), your effective input string to sscanf is "12,1.525,2.789", right?

Example 1:
Code:
 input: 12,1.525,2.789
  match: (%f->12)(,->,)(%f->1.525)(,->,)(%hhd->2)   (since the . is not a valid digit for an integer)
Example 2:
Code:
 input: 12,1.525,2.789
  match: (%f->12)(,->,)(%f->1.525)(,->,)(%hhd->2)   (note that your return value is three and not four, as the sscanf parser is stuck on the period and you are telling it to match a comma)
Example 3:
Code:
  input: 12,1.525,2.789
  match: (%f->12)(,->,)(%f->1.525)(,->,)(%hhd->2)   (still stuck on the period...)
Basically, you're trying to match the wrong type in example 2, the number 2.789 is a float, not an integer. If you were intentionally trying to break the float into pieces (storing 2 and 789 in different places), then your problem is the comma in sscanf format string doesn't match the period in your input.

Hope this helps!
 
Last edited by a moderator:

I'm using a Microchip C30 compiler on dsPIC33F family and struggling A LOT with sscanf() function. Please please please help me because my project is getting stuck for this little detail. I really hope that someone can help me, I haven't found anything on internet and I spent the last 2 days on this issue. Thanks a lot in advance.

-----------------------
IMPORTANT NOTE (10-Aug, 12:30pm PST): in my original post the "char string[] = ..." instructions in ALL three examples I reported (A, B and C below) were wrong due to a copy and paste mistake with code examples I took from my tests. I corrected these three examples as you can see below (see also the comment). Sorry for that!
-----------------------

THE TASK

I have to read different types of numbers from a string (unsigned int, float, char and unsigned char).

THE ISSUES :oops:

I have problems reading numeric char and unsigned char (i.e. 8 bit numbers, not ASCII characters), but not the other ones. With problem I mean that sscanf() fails (crashes) during its execution without returning any numeric value. In particular the problems come when I try to read more than one char (or unsigned char) in a row. As a char conversion specifier I use %hhd, but I tried - at least I think - with all the possible combinations. For unsigned char I used %hhu.
In order to understand better please look at this examples with just float and char. Float are read correctly, char just in case A) with one char parameter.

A) JUST ONE CHAR HAS TO BE READ: it works correctly :grin: :lol: :p

// 99 init values just for debugging resons

//char string[] = "test1 12,1.525,2.789"; -> WRONG INSTRUCTION I WROTE IN MY FIRST POST! PLEASE DON'T CONSIDER IT
char string[32] = "test1 1.525,2.789,12"; // THIS IS THE RIGHT ONE!

char theChar1 = 99;
float theFloat1;
float theFloat2;
int retVal = 99;

retVal = sscanf(&string[6],"%f,%f,%hhd",&theFloat1, &theFloat2, &theChar1);




B) TWO CHARS HAVE TO BE READ: it doesn't work, sscanf() does not complete its execution and doesn't provide a return value :-(

// 99 init values just for debugging resons

//char string[] = "test1 12,1.525,2.789"; -> WRONG INSTRUCTION I WROTE IN MY FIRST POST! PLEASE DON'T CONSIDER IT
char string[32] = "test1 1.525,2.789,12,13"; // THIS IS THE RIGHT ONE!

char theChar1 = 99;
char theChar2 = 99;
float theFloat1;
float theFloat2;
int retVal = 99;

retVal = sscanf(&string[6],"%f,%f,%hhd,%hhd",&theFloat1, &theFloat2, &theChar1, &theChar2);


C) THREE CHARS HAVE TO BE READ: it doesn't work, sscanf() does not complete its execution and doesn't provide a return value :-x

// 99 init values just for debugging resons

//char string[] = "test1 12,1.525,2.789"; -> WRONG INSTRUCTION I WROTE IN MY FIRST POST! PLEASE DON'T CONSIDER IT
char string[32] = "test1 1.525,2.789,12,13,14"; // THIS IS THE RIGHT ONE!

char theChar1 = 99;
char theChar2 = 99;
char theChar3 = 99;
float theFloat1;
float theFloat2;
int retVal = 99;

retVal = sscanf(&string[6],"%f,%f,%hhd,%hhd,%hhd",&theFloat1, &theFloat2, &theChar1, &theChar2, &theChar3);


THANKS SO MUCH FOR YOUR HELP!!!


To ALL,

Thanks SO MUCH for your replies, I really appreciate it. BUT, AS I SPECIFIED ABOVE IN RED IN THE POST, I MADE A "TERRIBLE" COPY AND PASTE MISTAKE IN MY CODE (in all cases, A, B and C). I CORRECTED IT IN MY ORIGINAL MESSAGE. NOW, IN THE ORIGINAL POST, YOU CAN SEE THE RIGHT CODE EXAMPLES.
In fact, during my tests, I tried to put the char arguments both at the beginning and at the end of the argument order in the sscanf (and so, consequently, the numbers in the source string). But in the code I posted I just pasted the source string "char string[] = ..." with one char (case A) at the beggining in ALL three cases. And I pasted the sscanf function call with the char arguments at the end of the variable list. I'm really sorry, I wrote this post after having worked 12 hours...

To kam1787:
At the beginning of krazyfencer reply you can find the explanation of the fact I'm using &string[6] (that is, with offset)

To krazyfencer:
I'm sorry, I just forgot to declare theChar3. I put it back in the post. Thanks for your explanations, unfortunately your considerations were based on the WRONG "char string[] = ..." definitions I wrote in my original post. I think that now everything makes more sense (hopefully).
 

Because the code example A) mentioned above provides the correct value to theChar1, I tried to run this example. Here I try to go around the issue getting the value of theChar1-3 executing three different sscanf instructions. You can read the result in capital among the comments.


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
// 99 init values just for debugging resons
char string[32] = "test1 1.525,2.789,12,13,14"; 
char theChar1 = 99;
char theChar2 = 99;
char theChar3 = 99;
float theFloat1;
float theFloat2;
int retVal = 99;
 
retVal = sscanf(&string[6],"%f,%f,%hhd,%hhd,%hhd",&theFloat1, &theFloat2, &theChar1);   // IN THIS INSTRUCTION ALL OK!
retVal = sscanf(&string[6],"%hhd", &theChar2);                                                                    // IT CRASHES
retVal = sscanf(&string[21],"%hhd", &theChar3);                                                                  // NOT EXECUTED


And, in case I don't use the last two instructions, it fails also if I replace them withe the following two:


Code C - [expand]
1
2
retVal = sscanf("13","%hhd", &theChar2);                                                                              // IT CRASHES
retVal = sscanf("14","%hhd", &theChar3);                                                                              // NOT EXECUTED


Any idea about the reason of the difference how the first and the second-third sscanf are executed?

Thanks so much!
 
Last edited by a moderator:

Hello,

Your problem is this line:

Code:
retVal = sscanf(&string[6],"%f,%f,%hhd,%hhd,%hhd",&theFloat1, &theFloat2, &theChar1); // IN THIS INSTRUCTION ALL OK!
You are telling sscanf that you have 2 floats and 3 bytes. Your are then passing in 2 floats and 1 byte. While this doesn't seem like a bad thing, it really is. sscanf uses what is called a vararg to allow you to pass any number of parameters to it (theFloat1, theFloat2, ...). However it uses the format string to tell it how many things you passed in and blindly obeys the format string. So when your format string says that you have more arguments than you really do, things go *crazy*. What is happening is that sscanf is popping more things off the stack than it pushed, and madness ensues. Replace this line with:


Code:
retVal = sscanf(&string[6],"%f,%f,%hhd",&theFloat1, &theFloat2, &theChar1); // IN THIS INSTRUCTION ALL OK!
or

Code:
retVal = sscanf(&string[6],"%f,%f,%hhd,%hhd,%hhd",&theFloat1, &theFloat2, &theChar1, &theChar2, &theChar3); // IN THIS INSTRUCTION ALL OK!
depeding on if you want to read them all or not. I hope this helps!
 
Last edited by a moderator:

Sorry for the late reply, but I'm overloaded of work and have the deadline this week.

To krazyfencer
I'm super-sorry again for the further copy and paste mistake. In the code I pasted on my previous post I actually wanted to write (and this is what I tested):


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
// 99 init values just for debugging resons
char string[32] = "test1 1.525,2.789,12,13,14";
char theChar1 = 99;
char theChar2 = 99;
char theChar3 = 99;
float theFloat1;
float theFloat2;
int retVal = 99;
 
retVal = sscanf(&string[6],"%f,%f,%hhd",&theFloat1, &theFloat2, &theChar1); // IN THIS INSTRUCTION ALL OK!
retVal = sscanf(&string[6],"%hhd", &theChar2); // IT CRASHES
retVal = sscanf(&string[21],"%hhd", &theChar3); // NOT EXECUTED



And, if I don't use the last two instructions, it fails also if I replace them withe the following two:


Code C - [expand]
1
2
retVal = sscanf("13","%hhd", &theChar2); // IT CRASHES
retVal = sscanf("14","%hhd", &theChar3); // NOT EXECUTED



But the issue is still present. In order to speed up my project because, unfortunately, I have to deliver this week, I went around the issue and found a solution that is not super-elegant but it works. It is:


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
char string[32] = "test1 1.525,2.789,12,13,14";
char theChar1 = 99;
char theChar2 = 99;
char theChar3 = 99;
int tempInt1 = 99;
int tempInt2 = 99;
int tempInt3 = 99;
float theFloat1;
float theFloat2;
int retVal = 99;
 
retVal = sscanf(&string[6],"%f,%f,%d,%d,%d",&theFloat1, &theFloat2, &int tempInt1, &int tempInt2, &int tempInt3);  // ALL OK HERE!
 
theChar1 = (char) tempInt1;
theChar2 = (char) tempInt2;
theChar3 = (char) tempInt3;



In my opinion it is not a stack issue. I say that without having deeply tested it, but I ran a test with a string much shorter of char string[32] = "test1 1.525,2.789,12,13,14"; above but still trying to get three char with %hhd. It is probably due to %hhd format that the function crashes. But unfortunately, in the Microchip documentation, I haven't found anything about how to get numeric char from sscanf.

Since I really don't like to go around to good solutions with the code I wrote above (even if it works), does anyone know what the solution is? It would be helpful for the community to know it. Thanks again to all, I really appreciate your help.
 
Last edited by a moderator:

Hello,

Okay, so I looked at your latest incarnation. The first piece of code in your latest post is correct, in that you can build it properly with a decent compiler (gcc) and it works as you would expect it to. If it is not working for you, I think you may have run into a limitation of the compiler (maybe their C library implementation goofed the %hhd parsing of sscanf arguments or something). I don't have the compiler and can't test that. However, if this is a problem with their standard library (which is *extremely*, *extremely* rare in real c implementations, but I suppose the hardware-focused compilers are a bit slip-shod), the best thing to do is just not use the problematic function (in this case sscanf).

Here is a little bit of code that will parse any string of the following format: "SOMETHING_NOT_SPACE NUM1,NUM2,NUM3,...,NUMN" where num can be either a float or an integer byte. Try it on your string. This code uses atoi,atof,strchr and strtok instead of sscanf to parse the string (which actually gives you more flexibility in dynamically handling strings of more arguments). The only downside to this code is:
1) it assumes the other c library functions (atoi,atof,strchr and strtok) work on your platform
2) you take up more memory (the union and structure have a bit of overhead per element, but we are not talking about very many of these)
3) it is slower as you must check the type as you merrily skip through the output (see the printMyStuff function)


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#define MAX_NUM_VALUES 20
#define TYPE_FLOAT       1
#define TYPE_BYTE        2
 
union value_contents
{
  float flt;
  char  byte;
};
 
struct extracted_value
{
  char type;
  union value_contents value;
};
 
static void parseMyString( char *string,
               int *numValues,
               struct extracted_value *values )
{
  /* note that strtok will blast your original string, so if you
     care about it, make a copy of it here and pass that to strtok.
     otherwise, blast away... */
  char *part = strtok(string, " ");
  
  /* if this didn't hit, we don't have a space in your string,
     so the input isn't following our assumed format */
  if ( !part )
    return;
 
  while ( (part = strtok(NULL, ",")) )
    {
      /* see if we've run out of room for our output */
      if ( *numValues >= MAX_NUM_VALUES )
    break;
 
      /* okay, we've got a nul terminated string (part) that we can
     play with.  First let's figure out if it is a float... */
      if ( strchr(part, '.') )
    {
      values[*numValues].type = TYPE_FLOAT;
      values[(*numValues)++].value.flt = atof(part);
    }
      else
    {
      values[*numValues].type = TYPE_BYTE;
      values[(*numValues)++].value.byte = atoi(part);
    }
    }
}
 
static void printMyStuff( int numValues,
              const struct extracted_value *values )
{
  int i;
  int numBytes = 0;
  int numFloats = 0;
  for ( i = 0; i < numValues; ++i )
    switch( values[i].type )
      {
      case TYPE_FLOAT:
    ++numFloats;
    printf("Extracted value #%d is a float = %0.3f\n", i+1, values[i].value.flt);
    break;
      case TYPE_BYTE:
    ++numBytes;
    printf("Extracted value #%d is a byte = %d\n", i+1, values[i].value.byte);
    break;
      }
  
  printf("Extracted %d byte%s.\n", numBytes, ((numBytes == 1) ? "" : "s"));
  printf("Extracted %d float%s.\n", numFloats, ((numFloats == 1) ? "" : "s"));
}
 
int main(int argc, char **argv)
{
  char string[32] = "test1 1.525,2.789,12,13,14";
  
  int numValues = 0;
  struct extracted_value values[MAX_NUM_VALUES];
 
  printf("Original input string: %s\n", string);
  parseMyString(string, &numValues, values);
  printMyStuff(numValues, values);
  return 0;
}



Anyways, let me know if that works out better than the sscanf situation. Good Luck!

Oh yeah, I'm a little confused about the third code section at the bottom of your last posting, which contains the code that you say is your fix. The "&int tempInt1" syntax in the sscanf line #12 doesn't compile for me (using gcc) and isn't legal C. Maybe your C30 compiler allows this? I'm not quite sure why it would, or what it would mean...
 
Last edited:

Hi krazyfencer,

Many thanks for your reply, I found your solution without sscanf very good and also very elegant in term of code styling. To tell you the truth I never used strtok function before but, reading your code and some further documentation (necessary because, at the first reading, it's not so easy to understand how strtok works. I needed also examples), I understood how this function works and found it very powerful. I'll use this code, I give up with sscanf. Thanks again!

As regards your last observation you are right. The code I put in the third portion of my last post is not correct in term of standard C. And C30 Microchip compiler doesn't compile it as well. The reason of that wrong code is (another) copy and paste mistake I made. The reason of all these copy and paste mistakes is that I actually used a different code in my examples from the one I posted (but super-similar) so, changing it in a more readable way, I made those mistakes. I apologize for the confusion.

Thanks again

- - - Updated - - -

In any case I cannot mark this post as solved, because it is related on how to extract char numbers (not characters) from a string using sscanf function with Microchip C30 compiler.
Thanks all for your replies.
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top