1

I have the function below in a file called WiServer.h for Arduino.

GETrequest(uint8* ipAddr, int port, char* hostName, char* URL);

Now the problem is I need to concatenate an int value (setting1) to the char* URL parameter like the below for example.

"twittermood.php?status=sendTweet&setting1="+setting1

I get an error:

invalid conversion from const char* to char*

How do I fix it?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
unleashed
  • 915
  • 2
  • 16
  • 35
  • 5
    Since you're not familiar with C++ I'll recommend [a good introductory C++ book](http://stackoverflow.com/q/388242/46642). – R. Martinho Fernandes Dec 07 '11 at 18:13
  • 4
    How in the world is that "not a real question"? I really sympathize with all the resentments of a seasoned C++ programmer against clueless Java coders being unleashed onto the C++ world, and have seen my share of such code — but it's a legitimate question according to the rules, and as an SO question it's not a bad one. – sbi Dec 07 '11 at 18:25
  • Coming from Java to C/C++ is tricky for us Java programmers. As much as I would love to learn C/C++, i'm doing a project in Arduino and came across this slight problem with pointers. I didn't expect to have these sort of responses and down votes and basically be told to F off and read a C++ Book. – unleashed Dec 07 '11 at 18:37
  • 1
    @FailedDev: I wasn't replying to you, I was addressing whoever had cast that close vote and to those who casted the downvotes. (FWIW, I had upvoted your comment.) – sbi Dec 07 '11 at 18:49

6 Answers6

9

You've gotten decent generic C++ advice, but for the special case of Arduino on an 8-bit AVR microcontroller I think you need platform-specific advice:

The Arduino runtime provides a String object. Your question is probably covered by these examples.

Because of the very limited RAM space on Arduino it is common to use special attributes to put constant strings in flash (essentially ROM) which requires different instructions to access. AVR code built with GCC is typically built on top of AVR Libc which has support for operating on a mix of constant strings and RAM strings. You must be explicit in your code and choose the right operations. This requires at least a basic understanding of how C strings work and how pointers work. I'm not sure how much of this cleverness is automatically provided by the Arduino String, but without this cleverness all of your string constants will end up copied into RAM at boot and will take up those precious bytes all the time.

If RAM space becomes a problem or you are working on an AVR application that does extensive string manipulation you need to learn how to use the mix of PGM Space operations (string functions that can work on read-only strings in flash) and regular C-style RAM-based string operations.

Ben Jackson
  • 90,079
  • 9
  • 98
  • 150
6

Use std::string, rather than C strings. Use string streams, rather than trying to concatenate non-string values to strings:

std::ostringstream oss;
oss << "twittermood.php?status=sendTweet&setting1=" << setting1;
use(oss.str()); // or use(oss.str().c_str());

If that API really needs a non-const string (given that it doesn't even take the length of the string, I suppose it's just a buggy API disregarding const), copy the string to a buffer and pass that:

const std::string& str = oss.str(); 
std::vector<char> buffer(str.begin(), str.end());
buffer.push_back('\0');
GETrequest(addr, port, &buffer[0], c);

As for what really happens when you do what you do:

"twittermood.php?status=sendTweet&setting1=" is an rvalue of the type char[43], which implicitly converts to const char*, a pointer to the first character. To that you add an integer, by this forming a new pointer of the type const char* pointing to some more or less random memory location. I suppose you try to pass this as the char* to your API function, for which the const would have to be dropped.

A C++ compiler, however, will never implicitly drop a const — for your own good.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
sbi
  • 219,715
  • 46
  • 258
  • 445
  • The fact that this was a good question is shown by the number of more or less incorrect/incomplete answers. +1 from me both to the (very good) answer and to the question (at least it's not -1 any longer!) – Francesco Dec 07 '11 at 19:18
2

Use a std::string, not a char*, for this sort of work. A char* in C is extremely basic and if you're not familiar with how C works, very easy to use wrong.

If you need to use char*, look into strcpy, strcat and snprintf. But these functions are very dangerous in a novice's hands and can lead to memory corruption and crashing.

StilesCrisis
  • 15,972
  • 4
  • 39
  • 62
1

You can use an ostringstream for this:

#include <sstream>

// ...

std::ostringstream os;
os << "twittermood.php?status=sendTweet&setting1=" << setting1;

GETrequest(addr, port, hostname, os.str().c_str());
R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
1

Use std::string instead of char* and maybe a std::stringstream for your concatination. But first about your errors:

Your problem is that "twittermood.php?status=sendTweet&setting1=" will get you a const char*, which can't be implicitely converted to a char*. If you are really sure that GETrequest doesn't try to change the value of its URL parameter, you can use const_cast<char*>(...) on your const char* variable to cast away the constness. However, do this only if you are absolutely sure it won't be changed (don't lie to the compiler about constness (or anything really)).

Even if you do that "twittermood.php?status=sendTweet&setting1="+setting1 won't do what you think it does. As I said your string constant will give you a const char*, which doesn't have any knowledge about string operations. So adding an intto it won't concat that int to the string, but instead do some pointerarithmetic, so if you are lucky and your int was small enough you get only a part of the URL, otherwise you will address something completely different.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Grizzly
  • 19,595
  • 4
  • 60
  • 78
0

Posting C solution for completeness:

const char ctext[] = "twittermood.php?status=sendTweet&setting1=";
char text[sizeof(ctext) + 20];
snprintf(text, sizeof(text), "%s%i", ctext, setting1);

std strings and streams are much nicer/safer to use.

Pubby
  • 51,882
  • 13
  • 139
  • 180
  • 1
    Of course, as a programmer this assures that you will still have a job a few years from now. But the job will be finding such stupid buffer overflows which make that phone prone to viruses, rather than writing exciting new stuff. – sbi Dec 07 '11 at 18:42
  • Why the downvote? The question was C style and so a C answer seems reasonable. – Pubby Dec 07 '11 at 19:02
  • 1
    Why the question? I already explained that there's a buffer overflow lurking in your code. (And the question is tagged C++.) – sbi Dec 07 '11 at 19:06
  • 1
    @sbi I don't see a buffer overflow, especially since Arduino is 8 bit. I changed it to use `snprintf` anyway. – Pubby Dec 07 '11 at 19:10
  • snprintf does not null terminate the buffer when it fills to the limit. – StilesCrisis Dec 07 '11 at 19:12
  • 1
    @StilesCrisis It does in my glibc. – Daniel Fischer Dec 07 '11 at 19:30
  • @Daniel: well, it does not in Windows, so it's not good to rely on if you want your code to work everywhere. – StilesCrisis Dec 07 '11 at 20:02
  • The buffer overflows comes when strlen( setting1 ) > 20. – Rob K Dec 07 '11 at 20:27
  • @StilesCrisis Yes, not every `snprintf` does. You're absolutely right that to be portable you have to 0-terminate yourself. I was just in a pedantic mood, and 'does not' is not entirely true. No offence meant. – Daniel Fischer Dec 07 '11 at 20:39
  • @Rob K: no 32 bit integer takes >20 characters to print out. – StilesCrisis Dec 07 '11 at 21:49
  • @StilesCrisis True, but where was it ever stated that setting1 was a 32 bit int? And what happens when it gets recompiled in a couple of years and becomes a 64 bit int? – Rob K Dec 07 '11 at 21:56
  • @Rob K: the original question stated that setting1 is an int and the architecture is an 8 bit microcontroller. If it ever becomes 64 bit, I think you would actually need a 21 character buffer. – StilesCrisis Dec 07 '11 at 22:13
  • 1
    @RobK 64 bits should fit, although I doubt arduino will ever be that big. – Pubby Dec 07 '11 at 22:13
  • 1
    @StilesCrisis 64 can't take up more than 20 characters. The null character is part of `sizeof(ctext)`. – Pubby Dec 07 '11 at 22:15