Understanding Spark.variable() function

Hey all,

I had a question on the syntax for the Spark.variable() function, with the following code:

int pos = 0;    
void setup()
{
     Spark.variable("position", &pos, INT);//THIS WORKS 
    Spark.variable("position", pos, INT);//THIS DOES NOT WORK 

}

I was wondering what the purpose of the & was.

Im used to web languages like(AS3, php, js) so I was confused on why it needs that &.

Also, does anyone have a suggestion on a good book/site to learn the code which spark is written in, is it(c++ ? )

Thanks!

@flashyourface, for Spark.variable, second parameter should be a pointer. In C/C++ the & operator returns the address of the variable. This docs explains that:

http://docs.spark.io/firmware/#spark-variable

1 Like

Thanks Krvarma this is making sense. I have 0 prior knowledge of c++ so setting variable pointers is a very new concept for me.

Also I have been using the docs alot and they do not expalin this-

“second parameter should be a pointer. In C/C++ the & operator returns the address of the variable”

as well as you.

Though, why doesnt the char var with the * need the & sign in its variable function?

Thanks!

@flashyourface, pointer is a variable that holds the address of another variable. A pointer to int can be declare as int* pInt;, so the pInt is a pointer variable that holds the address of another variable. A char pointer can be declared as char* pString = "This is for testing".

In the example described in the docs, char *message = "my name is spark"; The variable message is a pointer variable. So we don’t need to use & operator. But in case of int tempC = 0;, the tempC is not a pointer but a normal integer variable. To get the address the of the tempC variable you have to use the & operator. That’s why the & for the other tempC variable.

1 Like

@flashyourface The Spark Core code is written in C for Arduino, C, or C++. I’d say most of the examples are in C for Arduino (which is essentially C with added features for more convenient embedded programming).

For books on C check out The Definitive C Book Guide and List on Stack Overflow. I’d pick out one of the ‘Beginner’ books. I would definitely recommend studying up on C if your seriously interested in the embedded realm.

The following book Beginning C for Arduino: Learn C Programming for the Arduino and Compatible Microcontrollers has good ratings on Amazon.com, but I haven’t read it.

Hope this helps!

Thank you for that info @krvarma , it helps alot!

My challange is how to set that char var with another string set from a function, I would think this would work though it does not:

char *msg;

void setup()
{
     Spark.variable("mymessage", msg, STRING);
     
     changeMessage("HELLO");
}

int changeMessage(String message){
    
    msg = message;
    
    return 1;
}

it says - cannot convert ‘String’ to ‘char*’

however I thought a char was a string?

Thanks!

Also its kind of frustrating for me because I thought this would work and it actually does work, why would it be more difficult to do the same to a string:

int msg;

void setup()
{
     Spark.variable("mymessage", &msg, INT);
     changeMessage(9);
}

void loop()
{

}

int changeMessage(int newVal){
    
    msg = newVal;
    
    return 1;
}

Thanks alot @brett

Good question @flashyourface! This is a basic thing in C/C++, but I totally get how it’s confusing from a web language! :smiley:

Two things need to change.

Reserve memory for the string

Strings take up a variable amount of space. Each letter adds more memory that you need to reserve. The word used by C programmers for this is that you have to “allocate” memory for the string.

At the top, change char *msg; which only allocates enough space for the pointer to the string to char msg[100]; to reserve space for up to 99 characters. C strings always end with a null byte.

Use strcpy instead of equals

To make a copy of a string variable in C, you should use the strcpy function. Also String objects have a c_str() method to pull out the char*, so you should do this:

strcpy(msg, message.c_str());

Your integer code should work fine! :+1: What error are you getting?

2 Likes

Documentation for strcpy():
https://sourceware.org/newlib/libc.html#strcpy

Ah hey @zachary, thanks so much for that info it was super helpful. The IDE was happy with that code on verification however, when updating firmware it always goes to red and I have to reset everything, this is my code:

char *msg = "Default Value";

void setup(){
     Spark.variable("mymessage", msg, STRING);
     changeMessage("Great Success");
}

void loop(){}

void changeMessage(String newMessage){
    msg = strcpy(msg, newMessage.c_str());
}

What do you think the problem could be?

The integer version worked fine, I was just asking about it because I was confused why that worked and the char version didn’t.

Thanks!

OHHHHH I got it. That was my bad! I re read your post more carefully and came up with this(which works!!!):

char msg[100];
void setup(){
     Spark.variable("mymessage", msg, STRING);
     changeMessage("Great Success");
}
void loop(){}
void changeMessage(String newMessage){
     strcpy(msg, newMessage.c_str());
}

Thank you soooooooo much!

The only thing im confused about is that I thought that I needed the * to be a pointer and then when we switched to adding’[100]’(is that object or array?) does that still make it a pointer?

Thanks!

2 Likes

@flashyourface char msg[100] does define an array. But msg is a pointer to the array (of 100 characters). So that is why msg works in the line Spark.variable("mymessage", msg, STRING);

1 Like

A quick, little orientation to C strings

The char type means one character, like one letter. It’s a single byte. In C, single quotes surround characters, while double quotes surround strings. Single and double quotes are NOT interchangeable like they are in ruby, python, php, etc.

char oneCharacter = 'x';

Adding an asterisk makes the variable a pointer to a char. On a 32-bit architecture like the Spark Core, the address, the pointer, is 4 bytes long.

char *aString = "x";

In the above expression, the value of aString is some memory address—the memory address where the string starts. The value of *aString (which can be read as "the thing pointed to by aString") is the single character 'x'.

If we only know the address where the string starts, how can tell how long the string is?

C strings are “null terminated”. That means that there’s always an extra hidden '\0' character at the end of the string, which is how the machine knows where the string ends and how long the string is.

This is important to recognize! In the above expression *aString actually takes up 2 bytes: first the 'x' then the '\0'. That means that if you’re reserving memory for a string, you always need one more byte than you might think; to hold a string that’s 10 characters long, you need 11 bytes.

You can find out how long a C string is with strlen() (strlen newlib docs).

char *aString = "x";
strlen(aString); // returns 1

A common way to break your firmware is to try to write past the end of the memory you’ve reserved. Sometimes this causes a hard fault (SOS red flashing), but often it will quietly succeed, overwriting something else you did not expect to change.

The String class hides some of the complexity. Check out its documentation. When you need to get access to the internal C string wrapped up inside the String object, use its c_str() method.

String cppStringObject = "Why hello!";
char *cString = cppStringObject.c_str();

And remember, this is open source! The String class isn’t that scary. In addition to the Spark documentation, you can look at the source to understand how it works. As is usual with C++ classes, the String class is defined in a header file and an implementation file.

You usually reserve (or “allocate”) memory for a C string at the top of your program.

char message[100];

That expression is an array of characters. Also, perhaps a little confusingly, message is a pointer to a char. It’s just like char *message; except that the bracket syntax actually reserves space for the string in memory.

To refer to the first character of the string, you’d say message[0], and to refer to the second character message[1]. That’s just like most web languages. This is totally fine syntax:

char message[8];
message[0] = 'H';
message[1] = 'i';
message[2] = '!';
message[3] = '\0';

Pretty verbose though.

You would usually instead use strcpy() (strcpy newlib docs) to change the contents of a character array.

char message[50];
strcpy(message, "Hello world!");

Cheers!

4 Likes

wow @zachary thanks so much for posting that, it is super helpful to me.

That ‘quietly succeed’ you mentioned, sounds like it could cause some huge problems and is not something I would ever think would happen.

1 Like

You’re welcome! I just added a little to the post as well about the array bracket syntax.

I think it’s accurate to claim that the “quietly succeed” problem in C/C++ is the source of most of the security bugs you see in the world. They’re very hard to find. Heartbleed was an example of this kind of bug.

People refer to ways of preventing it with phrases like “bounds checking” (intuitive enough) or “canaries” (meaning you have constant “canary” values in “the coal mine” of memory that you just check and know to expect—if they change, you know you’ve encountered this kind of bug)

3 Likes