Pages: 1 [2]   Go Down
Author Topic: String to function: any best practices?  (Read 1811 times)
0 Members and 1 Guest are viewing this topic.
Amsterdam, Netherlands
Offline Offline
Jr. Member
**
Karma: 0
Posts: 52
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

@GoForSmoke Haha, yeah that is true as well. It's just that i don't understand why Arduino's String implementation is so much more RAM intensive, why don't they just use the char* functions but wrap them in a human-readable format - like string.compareTo instead of strcmpstrtoantrhstr() (to exacerbate what i'm trying to say here). I'm no C++ programmer, so i don't have these methods 'baked' into my mind, but i have used PHP which inherits a lot of the same function names and also there i found they weren't really human-readable. But this creates a whole different discussion which is not my point here).

Question regarding sscanf

I'm now using the sscanf function (which is awesome and saves a lot of roll-your-own-parser-time) this way:

void dataReceivedAction(WebSocket &socket, char* dataString, byte frameLength) {

// below debug print is a leftover from the example webSocketServer library.
#ifdef DEBUG
  Serial.print("Got data: ");
  Serial.write((unsigned char*)dataString, frameLength);
  //Serial.println("\n");
#endif

// first, extract command and params if there are any
  String command;
  String param1;
  String param2;
  
  int numExtracted = sscanf(dataString, "%s %s %s", &command, &param1, &param2);
  
  switch(numExtracted) {
    case 0:
        Serial.println("ERROR, ERROR, ERROR! NO VALID REQUEST FOUND.");
    break;
    
    case 1:
        Serial.println("extraction yielded only a function call.");
        Serial.println("command: ");
        Serial.println(command);
        Serial.println("\n\n");
    break;
    
    case 2:
        Serial.println("extraction yielded a function call + 1 parameter.");
        Serial.println("command: ");
        Serial.println(command);
        Serial.println("\n");
        Serial.println("param1: ");
        Serial.println(param1);
        Serial.println("\n\n");
    break;
    
    case 3:
        Serial.println("extraction yielded a function call + 2 parameters.");
        Serial.println("command: ");
        Serial.println(command);
        Serial.println("\n");
        Serial.println("param1: ");
        Serial.println(param1);
        Serial.println("\n");
        Serial.println("param2: ");
        Serial.println(param2);
        Serial.println("\n\n");
    break;
  }

}

But, when i run this, i get a lot of gibberish AFTER the debug line (see screenshot)
Something is not right with the way i use sscanf, can anyone point out what?
Also, i know my switch-case debug could probably written in a tenth the amount of lines so proposals are greatly welcomed!

[EDIT: i've now removed all the command and param serial.println's.]
no weird gibberish and also allmost real-time communication with my app, instead of a 3 second delay.

i've changed my switch statement to the following:

Serial.println("Extraction yielded a function call + " + String(numExtracted-1) + " parameter(s).");

which just only lets me know what the signature is of what is called, enough for now but i'd like to
show the name of the function and the parameters as well..

IP adress:
192.168.1.200
Got data: SET_Mode bla test

extraction yielded a function call + 2 parameters.
function GET_Speed called...
« Last Edit: June 14, 2012, 09:28:02 am by supermaggel » Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 309
Posts: 26529
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
String command;
  String param1;
  String param2;
 
  int numExtracted = sscanf(dataString, "%s %s %s", &command, &param1, &param2);

sscanf parses strings (char*) not Strings.
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

North Queensland, Australia
Offline Offline
Edison Member
*
Karma: 74
Posts: 2226
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hmmmm, I just examined zoomed through the string class. Seems some benefits can be gained here.

As I can tell,

Code:
char *buffer;         // the actual char array

is the first element. So something like the following is valid:

Code:
int numExtracted = sscanf( dataString, "%s %s %s", &command, ( char* ) &param1, ( char* ) &param2);

but there is more appropriate versions to this. The best being a core update:

Code:

class String{

  public:

    operator char*(){ return this->buffer; }  //Add this

    //Blah

  private:

    char *buffer;         // the actual char array

    //Blah
};

or without changing the core:

Code:
inline char *operator =( String &s_Str ){ return ( char* ) &s_Str; }

^^Have to cast due to buffer being private.
Logged


Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 98
Posts: 4817
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

C++ String class, when you change a String (at least when the size changes) makes a copy of itself including overhead bytes and deletes the original which leaves a hole in the heap. One of the 'conveniences' being that you don't 'see' it happen.
Maybe the next allocation will fit in the hole. Might even fill it. If it doesn't then it goes on the end and bumps the heap size up. At the same time, the stack grows and shrinks from the top of ram down. If heap and stack collide then what happens isn't something you can find through simple examination of your source logic.

Here are some signs and observations of the road ahead for beginners:

All the C string commands boil down to simple enough ideas that you can roll on your own. You need to be aware of your own buffer lengths and do bounds checks even if you use the built-ins. I really think from having rolled my own that making your own teaches enough to lose the mystery and fear of of commands like strcmp (string compare), to know that strncpy differs from strcpy by how each deals with number of characters copied and terminating zero. Strncpy does not place a terminating zero at the end of the copied section which is essential when changing characters in the middle of a string -- it is equal to the BASIC MIDSTR$() command.

Why prefer strcmp to stringCompareTo? Because I'm not a masochist. Because getting used to the abbreviated code takes a short while and it takes less thought-space too. That's why we shorten names and words, especially technical words, or have "big words" to replace whole sentences. It's the difference between in many cases English and German, two syllables vs many. OTOH many technical names in German tell just what a thing is or does in detail, like long variable names. But say them ten times fast, you can't. Long words are harder to think.

Setting up a flag and while loop to compare two arrays is drop dead simple once you've done it a time or two yet for those who have not there's some kind of dread. It takes more mental work to constantly come up with meaningful comments!

A pointer is a pointer, it's not the data, it only points to data. You add 1 to a byte pointer and it points to the next byte. You can walk through an array by setting a pointer to the start and incrementing the pointer as you go, it's like working with an index where you don't have to use the array name and brackets, it saves typing. There's even pointers to pointers, pointers to functions and pointer tables. Take a week or more to get the basics down and do the homework because pointers are one of the most versatile and powerful things in C.
 
The best part of high level for me means not having to know what CPU registers are being used. I use libraries when I need them but I know that behind every convenient function there are a couple to many lines of code and maybe (probably) some stack variables in addition to passed args.

If you use sscanf or atoi or any functions that can return an error (feed atoi "123foo") then check for error returned. It's easier to code for everything going right but that's wishful non-thinking unless you made sure in previous code. If you're that good then all of the above is old hat anyway.

Logged

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

UK
Offline Offline
Faraday Member
**
Karma: 100
Posts: 4153
Where is your SSCCE?!?!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
feed atoi "123foo"

It converts it to an integer containing 123.  atoi() converts the beginning of the string, so that is a perfectly valid string.  "foo123" would throw it more, in that it will return 0 smiley-wink
Logged

Get 10% off all 4D Systems TFT screens this month: use discount code MAJENKO10

Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 98
Posts: 4817
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

My input routines from 30+ years ago were tighter against mistakes. They had to be, they were used by fumble-typing engineers.

Logged

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 644
Posts: 50487
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
They had to be, they were used by fumble-typing engineers.
Hey, I resemble that remark!  smiley-cool
Logged

Pages: 1 [2]   Go Up
Jump to: