How to print strings with floats using Arduino's Serial.println - c++

I've been printing a combination of strings and numbers with Arduino's Serial.println() like:
Serial.println(((String)"some value: " + some_value);
And this seems to work for most types, but fails for floats, which give me the compilation error:
ambiguous overload for ‘operator+’ (operand types are ‘String’ and ‘float’)
I've tried different calls like:
Serial.println(((String)"some float:" + ((String)some_float));
Serial.println(((String)"some float: " + String(some_float));
Serial.println(((String)"some float: " + String(some_float, 2));
but they give similar errors. Arduino's docs on String seem to imply that these should work. What am I doing wrong?
Update
After correcting my original errors, I now have this issue:
Serial.println(String("some value: ") + String(some_value));
>> call of overloaded ‘String(float&)’ is ambiguous
I also tried:
Serial.println(String("some float: ") + String(some_float, 2));
>> call of overloaded ‘String(float&, int)’ is ambiguous

It should be something else. I tried now with an Arduino UNO this code:
float some_float;
void setup() {
Serial.begin(9600);
some_float = 13.3558;
}
void loop() {
Serial.println(String("some float: ") + String(some_float, 2));
delay(1000);
}
and the output is
some_float: 13.35
some_float: 13.35
some_float: 13.35
...

First, you have an extra open bracket in all of your tests.
Next, as the error says, you are attempting to add a float value to a String type. The docs say the + operator only supports adding two String types together.
You'll need to convert your float into a String then add the two Strings together. There is an example of this on the doc page you linked:
String stringOne = String(5.698, 3); // using a float and the decimal places
The last example you gave that gives 'similar errors' looks like it should work when you remove the extra open bracket, according to the docs.
EDIT: in reference to the new error message ">> call of overloaded ‘String(float&)’ is ambiguous" can you paste some additional code to show at least:
- the definitions of some_float and some_value
- any namespaces you are including (e.g. std etc)
Generally with these sorts of problems, you should reduce the code to the simplest example which shows the error and post that whole example in the thread. (Quite often when you reduce it to the simplest example, you learn what the problem is anyway!)
The error says that String(float&) is ambiguous, so I'm guessing you have another namespace with a String definition in it which is conflicting with the Arduino version.

Related

Matlab regex ${numberFun($4)} - Undefined function 'numberFun' for input arguments of type 'char'

I read that in Matlab it is possible to include a function call inside a regex transformation like this $1double$2[${doubleTextNumber($4)}], assuming 1, 2, 3 to be some regex groups, and 4 to be a purely numeric group. The exact thing I want to do is to catch all arrays consisting of the type creal_T, replace the type with double and double the length of the array.
codeText = "typedef struct {
double tolRob;
creal_T Mt2o[704];
creal_T Ho2o[704];
creal_T Ht2t[704];
creal_T Zo2t[704];
creal_T Ztd[64];
} testType;"
So, I want the struct above to become:
typedef struct {
double tolRob;
double Mt2o[1408];
double Ho2o[1408];
double Ht2t[1408];
double Zo2t[1408];
double Ztd[128];
} SpdEstType;
In Matlab I have made a function to convert a number to text and double it:
function [doubleValue] = doubleTextNumber(inputNumber)
doubleValue = string(str2double(inputNumber)*2.0);
end
I also have a regex that I expect would find the number in each declaration and feed it to the function:
resultString = regexprep(
codeText,
'(?m)^(\W*)creal_T(\s*\w*)(\[([^\]]*\d+)\])',
"$1double$2[${doubleTextNumber($4)}]");
However, as I run this peace of code, Matlab gives me the following error msg:
Error using regexprep
Evaluation of 'doubleTextNumber($4)' failed:
Undefined function 'doubleTextNumber' for input arguments of type 'char'.
As far as I understand, I have made the method do conversion from char, and expect it also to accept this value from my regex. I have tested that it works when I input '704' or "704" directly, and also that the regex works appart from this insertion.
Why does not Matlab find the function from my regex? (they are in the same m file)
It looks like I had 3 issues with my original approach:
In order for regexprep() to recognize my function, it had to be moved to its own m-file. Simply calling a method from inside the same file did not work.
I was using https://regex101.com/ to edit the search expression, but even though it seemed to be selecting the number inside the brackets, group 4 did not get populated by regexprep() in Matlab. A new version did work, and populated group 3 with the numbers I wanted: (?m)^(\W*)creal_T(\s*\w*).([^\]]*\d*)\]
I also added more conversion options to my multiplication method in case the input was a combination of numbers and char arrays.
The final version of my regex call becomes:
resultString = regexprep(
codeText,
'(?m)^(\W*)creal_T(\s*\w*).([^\]]*\d*)\]',
"$1double$2[${multiplyTextNumbers($3,2)}]");
where multiplyTextNumbers() is defined in its own m file as
function [productText] = multiplyTextNumbers(inputFactorText1,inputFactorText2)
%MULTIPLY This method takes numbers as input, and acepts either string,
%char or double or any combination of the three. Returns a string with the
%resulting product.
if (isstring(inputFactorText1) || ischar(inputFactorText1))
inputFactor1 = str2double(inputFactorText1);
else
inputFactor1 = inputFactorText1;
end
if (isstring(inputFactorText2) || ischar(inputFactorText2))
inputFactor2 = str2double(inputFactorText2);
else
inputFactor2 = inputFactorText2;
end
productText = sprintf('%d',inputFactor1*inputFactor2);
end
Hope this can be helpefull to others facing similar issues.

c++ error: no matching function for call to ‘std::__cxx11::basic_string<char>::append<int>(int, int)’

Trying to run this:
// appending to string
#include <iostream>
#include <string>
int
main()
{
std::string str;
std::string str2 = "Writing ";
std::string str3 = "print 10 and then 5 more";
// used in the same order as described above:
str.append(str2); // "Writing "
str.append(str3, 6, 3); // "10 "
str.append("dots are cool", 5); // "dots "
str.append("here: "); // "here: "
str.append(10u, '.'); // ".........."
str.append(str3.begin() + 8, str3.end()); // " and then 5 more"
str.append<int>(5, 0x2E); // "....."
std::cout << str << '\n';
return 0;
}
But having error on str.append(5,0x2E):
error: no matching function for call to ‘std::__cxx11::basic_string::append(int, int)’
Using VS Code 1.43.1, running on ubuntu 19.10, gcc version 9.2.1 20191008 (Ubuntu 9.2.1-9ubuntu2).
I've tried to run the code on Code::Blocks 16.01 IDE, and windows, but had same error.
You need to convert 0x2E (integer) to char: char(0x2E) first.
str.append<int>(5,char(0x2E));
When having problems with the standard template library, you can always take a look at the c++ reference of the function you're using: http://www.cplusplus.com/reference/string/string/append/
In this case, there isn't any reason to specify the after your append: When doing this, both arguments get interpreted as an int, while you want the second to be interpreted as a char. You can simply achieve this by doing str.append(5,0x2E);. Your compiler will search the closest matching function, which is string& append (size_t n, char c); and implicitly convert the second argument to a char.
You just don't need the <int> part. str.append(5, 0x2E); compiles fine.
There is no variant of std::string::append() that takes two integers - you should make the second parameter a character, as there is a variant that takes an integer and a character.
In addition, by using <int>, you change the templated character type charT into an integer rather than a character, which is probably not going to work the way you expect. A std::string is generally defined as std::basic_string<char> so appending with .append<int> is going to have weird effects on the underlying memory at best.
Since you're wanting to add five more . characters, I'm not sure why you wouldn't just do:
str.append(5, '.');

Variable in Parentheses C++

I am currently in the process of writing up a C++ program that randomly chooses roles for people using file input/output.
I am almost done, and I build often to make sure my code is working and not psuedocode. I received an error on my snippet of code -
randomPrefs.open ("Preferences/"members[random]"-Preferences");
I am trying to access the text file in Preferences/foo-Preferences, and the variable is made random by some code above it. I have couted the random snippet and it works perfectly, so I need not include it here. The error I get is :
Avalon - Omnipotent.cpp:61:21: error: unable to find string literal operator 'operator""members' with 'const char [13]', 'unsigned int' arguments
And so, I have searched around for this error but have found nothing. I thought of making a mini-parentheses around it, and it resulted in a different error -
Avalon - Omnipotent.cpp:61:51: error: expression cannot be used as a function
Any help would be appreciated.
A little note down here, when not having the parentheses around it, I get a warning about my variable not being used -
Avalon - Omnipotent.cpp:39:21: warning: unused variable 'members' [-Wunused-variable]
However, the second error does not give a warning about the unused variable.
Hey is what my variable looks like:
unsigned const char members[22] =
And I assigned the value "random" which selects a random number from 0 - 21 and I assign the number generated to value random, and declare the variable as members[random]. It works perfectly, I just need help with these errors.
Help!
To concatenate strings, do the following:
std::string s = std::string("Preferences/") + members[random] + "-Preferences";
randomPrefs.open(s);
If you don't want the intermediate named variable, then:
randomPrefs.open(std::string("Preferences/") + members[random] + "-Preferences");
If members doesn't contain characters like 'A', 'B', 'C', or '4', and instead contains the number 4, 28, or 153, then you can convert the number to the appropriate string by using std::to_string.
std::string s = std::string("Preferences/") + std::to_string(members[random]) + "-Preferences");
The warning about the unused variable isn't useful, and is due to the compiler seeing earlier errors in your code. If you fix the above, that should also go away.
If you're trying to do string concatenation, it is probably best to use itoa() -> std::string(const char*) or to_string() for the number to string, and use operator+() or std::string.append() to do concatenation.
Note that to_string() is C++11:
http://coliru.stacked-crooked.com/a/eb3677d7abffca00
#include <iostream>
#include <string>
int main() {
std::string str1 = "Hello ";
int i = 2;
std::string str2 = " World!";
std::string output = "";
output.append(str1).append(std::to_string(i)).append(str2);
std::cout << output << std::endl;
return 0;
}
#YoBro: HERE! – Bill Lynch 7 mins ago
Modelling a bit of my code after his made it work!
std::string s = std::string("Preferences/") + std::to_string(members[random]) + "-Preferences";
randomPrefs.open(s);
I now use something similar to that.

How to cleanly use: const char* and std::string?

tl:dr
How can I concatenate const char* with std::string, neatly and
elegantly, without multiple function calls. Ideally in one function
call and have the output be a const char*. Is this impossible, what
is an optimum solution?
Initial Problem
The biggest barrier I have experienced with C++ so far is how it handles strings. In my opinion, of all the widely used languages, it handles strings the most poorly. I've seen other questions similar to this that either have an answer saying "use std::string" or simply point out that one of the options is going to be best for your situation.
However this is useless advice when trying to use strings dynamically like how they are used in other languages. I cannot guaranty to always be able to use std::string and for the times when I have to use const char* I hit the obvious wall of "it's constant, you can't concatenate it".
Every solution to any string manipulation problem I've seen in C++ requires repetitive multiple lines of code that only work well for that format of string.
I want to be able to concatenate any set of characters with the + symbol or make use of a simple format() function just how I can in C# or Python. Why is there no easy option?
Current Situation
Standard Output
I'm writing a DLL and so far I've been output text to cout via the << operator. Everything has been going fine so far using simple char arrays in the form:
cout << "Hello world!"
Runtime Strings
Now it comes to the point where I want to construct a string at runtime and store it with a class, this class will hold a string that reports on some errors so that they can be picked up by other classes and maybe sent to cout later, the string will be set by the function SetReport(const char* report). So I really don't want to use more than one line for this so I go ahead and write something like:
SetReport("Failure in " + __FUNCTION__ + ": foobar was " + foobar + "\n"); // __FUNCTION__ gets the name of the current function, foobar is some variable
Immediately of course I get:
expression must have integral or unscoped enum type and...
'+': cannot add two pointers
Ugly Strings
Right. So I'm trying to add two or more const char*s together and this just isn't an option. So I find that the main suggestion here is to use std::string, sort of weird that typing "Hello world!" doesn't just give you one of those in the first place but let's give it a go:
SetReport(std::string("Failure in ") + std::string(__FUNCTION__) + std::string(": foobar was ") + std::to_string(foobar) + std::string("\n"));
Brilliant! It works! But look how ugly that is!! That's some of the ugliest code I've every seen. We can simplify to this:
SetReport(std::string("Failure in ") + __FUNCTION__ + ": foobar was " + std::to_string(foobar) + "\n");
Still possibly the worst way I've every encounter of getting to a simple one line string concatenation but everything should be fine now right?
Convert Back To Constant
Well no, if you're working on a DLL, something that I tend to do a lot because I like to unit test so I need my C++ code to be imported by the unit test library, you will find that when you try to set that report string to a member variable of a class as a std::string the compiler throws a warning saying:
warning C4251: class 'std::basic_string<_Elem,_Traits,_Alloc>' needs to have dll-interface to be used by clients of class'
The only real solution to this problem that I've found other than "ignore the warning"(bad practice!) is to use const char* for the member variable rather than std::string but this is not really a solution, because now you have to convert your ugly concatenated (but dynamic) string back to the const char array you need. But you can't just tag .c_str() on the end (even though why would you want to because this concatenation is becoming more ridiculous by the second?) you have to make sure that std::string doesn't clean up your newly constructed string and leave you with garbage. So you have to do this inside the function that receives the string:
const std::string constString = (input);
m_constChar = constString.c_str();
Which is insane. Because now I traipsed across several different types of string, made my code ugly, added more lines than should need and all just to stick some characters together. Why is this so hard?
Solution?
So what's the solution? I feel that I should be able to make a function that concatenates const char*s together but also handle other object types such as std::string, int or double, I feel strongly that this should be capable in one line, and yet I'm unable to find any examples of it being achieved. Should I be working with char* rather than the constant variant, even though I've read that you should never change the value of char* so how would this help?
Are there any experienced C++ programmers who have resolved this issue and are now comfortable with C++ strings, what is your solution? Is there no solution? Is it impossible?
The standard way to build a string, formatting non-string types as strings, is a string stream
#include <sstream>
std::ostringstream ss;
ss << "Failure in " << __FUNCTION__ << ": foobar was " << foobar << "\n";
SetReport(ss.str());
If you do this often, you could write a variadic template to do that:
template <typename... Ts> std::string str(Ts&&...);
SetReport(str("Failure in ", __FUNCTION__, ": foobar was ", foobar, '\n'));
The implementation is left as an exercise for the reader.
In this particular case, string literals (including __FUNCTION__) can be concatenated by simply writing one after the other; and, assuming foobar is a std::string, that can be concatenated with string literals using +:
SetReport("Failure in " __FUNCTION__ ": foobar was " + foobar + "\n");
If foobar is a numeric type, you could use std::to_string(foobar) to convert it.
Plain string literals (e.g. "abc" and __FUNCTION__) and char const* do not support concatenation. These are just plain C-style char const[] and char const*.
Solutions are to use some string formatting facilities or libraries, such as:
std::string and concatenation using +. May involve too many unnecessary allocations, unless operator+ employs expression templates.
std::snprintf. This one does not allocate buffers for you and not type safe, so people end up creating wrappers for it.
std::stringstream. Ubiquitous and standard but its syntax is at best awkward.
boost::format. Type safe but reportedly slow.
cppformat. Reportedly modern and fast.
One of the simplest solution is to use an C++ empty string. Here I declare empty string variable named _ and used it in front of string concatenation. Make sure you always put it in the front.
#include <cstdio>
#include <string>
using namespace std;
string _ = "";
int main() {
char s[] = "chararray";
string result =
_ + "function name = [" + __FUNCTION__ + "] "
"and s is [" + s + "]\n";
printf( "%s", result.c_str() );
return 0;
}
Output:
function name = [main] and s is [chararray]
Regarding __FUNCTION__, I found that in Visual C++ it is a macro while in GCC it is a variable, so SetReport("Failure in " __FUNCTION__ "; foobar was " + foobar + "\n"); will only work on Visual C++. See: https://msdn.microsoft.com/en-us/library/b0084kay.aspx and https://gcc.gnu.org/onlinedocs/gcc/Function-Names.html
The solution using empty string variable above should work on both Visual C++ and GCC.
My Solution
I've continued to experiment with different things and I've got a solution which combines tivn's answer that involves making an empty string to help concatenate long std::string and character arrays together and a function of my own which allows single line copying of that std::string to a const char* which is safe to use when the string object leaves scope.
I would have used Mike Seymour's variadic templates but they don't seem to be supported by the Visual Studio 2012 I'm running and I need this solution to be very general so I can't rely on them.
Here is my solution:
Strings.h
#ifndef _STRINGS_H_
#define _STRINGS_H_
#include <string>
// tivn's empty string in the header file
extern const std::string _;
// My own version of .c_str() which produces a copy of the contents of the string input
const char* ToCString(std::string input);
#endif
Strings.cpp
#include "Strings.h"
const std::string str = "";
const char* ToCString(std::string input)
{
char* result = new char[input.length()+1];
strcpy_s(result, input.length()+1, input.c_str());
return result;
}
Usage
m_someMemberConstChar = ToCString(_ + "Hello, world! " + someDynamicValue);
I think this is pretty neat and works in most cases. Thank you everyone for helping me with this.
As of C++20, fmtlib has made its way into the ISO standard but, even on older iterations, you can still download and use it.
It gives similar capabilities as Python's str.format()(a), and your "ugly strings" example then becomes a relatively simple:
#include <fmt/format.h>
// Later on, where code is allowed (inside a function for example) ...
SetReport(fmt::format("Failure in {}: foobar was {}\n", __FUNCTION__, foobar));
It's much like the printf() family but with extensibility and type safety built in.
(a) But, unfortunately, not its string interpolation feature (use of f-strings), which has the added advantage of putting the expressions in the string at the place where they're output, something like:
set_report(f"Failure in {__FUNCTION__}: foobar was {foobar}\n");
If fmtlib ever got that capability, I'd probably wet my pants in excitement :-)

How to find in my program a "const char* + int" expression

I'm in a source code migration and the converter program did not convert concatenation of embedded strings with integers. Now I have lots of code with this kind of expressions:
f("some text" + i);
Since C/C++ will interpret this as an array subscript, f will receive "some text", or "ome text", or "me text"...
My source language converts the concatenation of an string with an int as an string concatenation. Now I need to go line by line through the source code and change, by hand, the previous expression to:
f("some text" + std::to_string(i));
The conversion program managed to convert local "String" variables to "std::string", resulting in expressions:
std::string some_str = ...;
int i = ...;
f(some_str + i);
Those were easy to fix because with such expressions the C++ compiler outputs an error.
Is there any tool to find automatically such expressions on source code?
Easy! Just replace all the + with -&:
find . -name '*.cpp' -print0 | xargs -0 sed -i '' 's/+/-\&/g'
When trying to compile your project you will see, between other errors, something like this:
foo.cpp:9:16: error: 'const char *' and 'int *' are not pointers to compatible types
return f(s -& i);
~ ^~~~
(I'm using clang, but other compilers should issue similar errors)
So you just have to filter the compiler output to keep only those errors:
clang++ foo.cpp 2>&1 | grep -F "error: 'const char *' and 'int *' are not pointers to compatible types"
And you get:
foo.cpp:9:16: error: 'const char *' and 'int *' are not pointers to compatible types
foo.cpp:18:10: error: 'const char *' and 'int *' are not pointers to compatible types
You can try flint, an open-source lint program for C++ developed and used at Facebook. It has blacklisted token sequences feature (checkBlacklistedSequences). You can add your token sequence to the checkBlacklistedSequences function and flint will report them.
in checkBlacklistedSequences function, I added the sequence string_literal + number
BlacklistEntry([tk!"string_literal", tk!"+", tk!"number"],
"string_literal + number problem!\n",
true),
then compile and test
$ cat -n test.cpp
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 void f(string str)
7 {
8 cout << str << endl;
9 }
10
11 int main(int argc, char *argv[])
12 {
13 f("Hello World" + 2);
14
15 f("Hello World" + std::to_string(2));
16
17 f("Hello World" + 2);
18
19 return 0;
20 }
$ ./flint test.cpp
test.cpp(13): Warning: string_literal + number problem!
test.cpp(17): Warning: string_literal + number problem!
flint has two versions (old version developed in C++ and new version in D language), I made my changes in D version.
I'm not familiar with a lot of tools which can do that, but I think grep can be helpful in some measure.
In the root directory of your source code, try:
grep -rn '".\+"\s*+\s*' .
, which can find out all the files which containt a line like "xxxxx" +, hope this can help you find all the lines you need.
If all the integers are constant, you can alter the grep experssion as:
grep -rn '".\+"\s*+\s*[0-9]*' .
And you can also include the ( before the string constant:
grep -rn '(".\+"\s*+\s*[0-9]*' .
This may be not the "correct" answer, but I hope this can help you.
You may not need an external tool. Instead, you can take advantage of C++ one-user-defined-conversion rule. Basically, you need to change the argument of your f function from const char*/std::string to a type, that is implicitly convertible only from either a string literal (const char[size]) or an std::string instance (what you get when you add std::to_string in the expression).
#include <string>
#include <iostream>
struct string_proxy
{
std::string value;
string_proxy(const std::string& value) : value(value) {}
string_proxy(std::string&& value) : value(std::move(value)) {}
template <size_t size>
string_proxy(const char (&str)[size]) : value(str) {}
};
void f(string_proxy proxy)
{
std::cout << proxy.value << std::endl;
}
int main()
{
f("this works"); // const char[size]
f("this works too: " + std::to_string(10)); // std::string
f("compile error!" + 10); // const char*
return 0;
}
Note that this is not going to work on MSVC, at least not in 2012 version; it's likely a bug, since there are no warning emitted either. It works perfectly fine in g++ and clang (you can quickly check it here).
I've found a very simple way to detect this issue. Regular expression nor a lint won't match more complex expressions like the following:
f("Hello " + g(i));
What I need is to somehow do type inference, so I'm letting the compiler to do it. Using an std::string instead of a literal string raises an error, so I wrote a simple source code converter to translate all the string literals to the wrapped std::string version, like this:
f(std::string("Hello ") + g(i));
Then, after recompiling the project, I'd see all the errors. The source code is on GitHub, in 48 lines of Python code:
https://gist.github.com/alejolp/3a700e1730e0328c68de
If your case is exactly as
"some text in quotations" + a_numeric_variable_or_constant
then Powergrep or similar programs will let you to scan all files for
("[^"]+")\s*\+\s*(\w+)
and replace with
\1 + std::to_string(\2)
This will bring the possible matches to you but i strongly recommend first preview what you are replacing. Because this will also replace the string variables.
Regular expressions cannot understand the semantics of your code so they cannot be sure that if they are integers. For that you need a program with a parser like CDT or static code analyzers. But unfortunately i do not know any that can do that. So to sum i hope regex helps :)
PS: For the worst case if the variables are not numeric then compiler will give you error because to_string function doesn't accept anything than numeric values. May be later then you can manually replace only them which i can only hope won't be more.
PS 2: Some may think that Powergrep is expensive. You can use trial for 15 day with full functionality.
You can have a try at the Map-Reduce Clang plugin.
The tool was developped at Google to do just this kind of refactoring, mixing strong type-checking and regexp.
(see video presentation here ).
You can use C++ typecasting operator & create a new class which can overload the operator + to your need. You can replace the int to new class "Integer" & perform the required overloading. This requires no changes or word replacing in the main function invocation.
class Integer{
long i;
std::string formatted;
public:
Integer(int i){i = i;}
operator char*(){
return (char*)formatted.c_str();}
friend Integer operator +( char* input, Integer t);
};
Integer operator +( char* input, Integer integer) {
integer.formatted = input + std::to_string(integer.i);
return integer;
}
Integer i = ....
f("test" + i); //executes the overloaded operator
i'm assuming for function f(some_str + i); your definition should be like this
void f(std::string value)
{
// do something.
}
if you declare some other class like AdvString to implement Operator + for intergers. if your declare your function like this below code. it will work like this implementation f(some_str + i);
void f(AdvString value)
{
// do something.
}
sample implementation is here https://github.com/prasaathviki/advstring