I am in the processes of building my first C++ application and choosing an efficient C++ libraries to rely on at this stage, is one of the design consideration I am looking at.
Consequently I want to convert an integer type to string and deciding on whether to use;
sprintf(string, "%d", x);
Or
Integer to ASCI
itoa(x, string);
Can anyone suggest which one of these route is efficient and possibly why?
Thanks.
They're both efficient. It's probably much more relevant to note that itoa() is not part of the C++ standard, and as such is not available in many common runtimes. (In particular, it's not part of libstdc++, so it's not available on Mac OS X or Linux.)
Don't use either of these. Use std::stringstream and so on.
std::stringstream ss;
ss << x;
ss.str(); // Access the std::string
Either way, it's quite unlikely that converting to string will be a significant part of your application's execution time.
From a pure algorithm viewpoint one can argue that itoa would be faster since sprintf has the additional cost of parsing the format descriptor string. However without benchmarking the cost of the two functions in an implementation, with a non-trivial work load, one cannot be sure.
Also this isn't apples to apples comparison since both functions aren't equivalent. sprintf can do much more formatting than itoa does, apart from the fact that the former is a standard function while the latter isn't.
Aside: If you can use C++11 you can use to_string which returns you an std::string. If you want representations other than decimal you may do this:
int i = 1234;
std::stringstream ss;
ss << std::hex << i; // hexadecimal
ss << std::oct << i; // octal
ss << std::dec << i; // decimal
std::bitset<sizeof(int) * std::numeric_limits<unsigned char>::digits> b(i);
ss << b; // binary
std::string str = ss.str();
Related
I have a code in C++ that's suppose to work on Linux and Windows.
Part of the code includes using vsnprintf in order to get a string using a format string and params.
I notices that whenever the format string contains %p the results are different on Linux and Windows - Windows doesn't prefix the result with 0x while linux does, and also windows uses uppercase for the letters of the address while Linux uses lowercase.
I couldn't find flags to make the two versions be identical.
My preference is to make the Linux version behave like the Windows one (since the Windows code is the original so that's how the program is expected to behave).
And if it's not possible to change the behavior of vsnprintf in Linux i would like a method to "fix" the strings that contain %p after vsnprintf outputs them (in an efficient way).
The string %p prints is implementation defined. That's why the behaviour is different on Linux and Windows. If you wanted consistent behaviour, you'd have to implement your own version.
Using uintptr_t, we can have an integer that can hold a pointer. So we can reinterpret_cast the pointer into it. Note that, although the conversion will succeed, it's not specified what the value will hold.
Then, we can print the integer as hex, either using std::hex or the appropriate format macro constant:
auto* myPointer = ...;
std::cout << std::hex << reinterpret_cast<std::uintptr_t>(myPointer) << '\n';
std::printf("%" PRIxPTR "\n", reinterpret_cast<std::uintptr_t>(myPointer));
Demo
The exact formatting would be up to you.
As Justin's answer suggests, you can convert the pointer to uintptr_t and format it as you like. This is likely to be 99% portable -- and since you're probably concerned with just Linux and Windows, that's probably good enough. (It can fail on a system where no integer type is big enough to hold a pointer value without loss of information. Such a system won't define uintptr_t. You're unlikely to encounter such a system.)
Another approach is to format the pointer as a string using a %p format, and then manipulate the resulting string to get the consistent results you want. It probably makes sense to create a function that takes a void* argument and returns a std::string.
Here's my attempt (I make no claim that this is good C++ code). It deletes a leading 0x or 0X if it exists, and it maps all remaining characters to upper case.
Tweak the for loop if you don't have a C++11 compiler.
#include <iostream>
#include <string>
#include <cstdio>
#include <cctype>
std::string hex(void* ptr) {
const int big_enough = 100;
char s[big_enough];
std::snprintf(s, sizeof s, "%p", ptr);
std::string result = s;
std::string prefix = result.substr(0, 2);
if (prefix == "0x" || prefix == "0X") {
result = result.substr(2);
}
for (auto &&c : result) {
c = std::toupper((unsigned char)c);
}
return result;
}
int main() {
int n;
int *ptr = &n;
std::printf("Using %%p: %p\n", (void*)ptr);
std::cout << "Using hex(): " << hex((void*)ptr) << "\n";
}
The output on my Linux system is:
Using %p: 0x7ffd6e8ca884
Using hex(): 7FFD6E8CA884
I have a string containing hexadecimal values (two characters representing a byte). I would like to use std::stringstream to make the conversion as painless as possible, so I came up with the following code:
std::string a_hex_number = "e3";
{
unsigned char x;
std::stringstream ss;
ss << std::hex << a_hex_number;
ss >> x;
std::cout << x << std::endl;
}
To my biggest surprise this prints out "e" ... Of course I don't give up so easily, and I modify the code to be:
{
unsigned short y;
std::stringstream ss;
ss << std::hex << a_hex_number;
ss >> y;
std::cout << y << std::endl;
}
This, as expected, prints out 227 ...
I looked at http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/ and http://www.cplusplus.com/reference/ios/hex/ but I just could not find a reference which tells me more about why this behaviour comes ...(yes, I feel that it is right because when extracting a character it should take one character, but I am a little bit confused that std:hex is ignored for characters). Is there a mention about this situation somewhere?
(http://ideone.com/YHt7Fz)
Edit I am specifically interested if this behaviour is mentioned in any of the STL standards.
If I understand correctly, you're trying to convert a string in
hex to an unsigned char. So for starters, since this is
"input", you should be using std::istringstream:
std::istringstream ss( a_hex_number );
ss >> std::hex >> variable;
Beyond that, you want the input to parse the string as an
integral value. Streams do not consider character types as
numeric values; they read a single character into them (after
skipping leading white space). To get a numeric value, you
should input to an int, and then convert that to unsigned
char. Characters don't have a base, so std::hex is
irrelevant for them. (The same thing holds for strings, for
example, and even for floating point.)
With regards to the page you site: the page doesn't mention
inputting into a character type (strangely enough, because it
does talk about all other types, including some very special
cases). The documentation for the std::hex manipulator is
also weak: in the running text, it only says that "extracted
values are also expected to be in hexadecimal base", which isn't
really correct; in the table, however, it clearly talks about
"integral values". In the standard, this is documented in
ยง27.7.2.2.3. (The >> operators for character types are not
member functions, but free functions, so are defined in
a different section.) What we are missing, however, is a good
document which synthesizes these sort of things: whether the
>> operator is a member or a free function doesn't really
affect the user much; you want to see all of the >> available,
with their semantics, in one place.
Let's put it simple: variable type is 'stronger' than 'hex'. That's why 'hex' is ignored for 'char' variable.
Longer story:
'Hex' modifies internal state of stringstream object telling it how to treat subsequent operations on integers. However, this does not apply to chars.
When you print out a character (i.e. unsigned char), it's printed as a character, not as a number.
The code below shows 2 solutions (std::to_string and std::stringstream) that convert an int m_currentSoundTime to std::string. Is std::to_string or std::stringstream faster?
// Compute current sound time in minute and convert to string
stringstream currentTime;
currentTime << m_currentSoundTime / 60;
m_currentSoundTimeInMinute = currentTime.str();
or
m_currentSoundTimeInMinute = to_string( m_currentSoundTime / 60 );
In any reasonable library implementation to_string will be at least as fast as stringstream for this. However, if you wanted to put 10 ints into a string, stringstream will likely be faster. If you were to do to_string(a) + ", " + to_string(b) + /*...*/ every operation would probably cause an allocation and a copy from the previous string to the new allocation - not true with stringstream.
More importantly, it's pretty obvious from your example code that to_string is cleaner for dealing with converting a single int to a string.
This blog post tests several int-to-string conversion methods (using GCC 4.7 on Ubuntu 13.04). In this
case to_string is somewhat slower than stringstream. But this probably depends strongly on the compiler and std library.
It seems to me that defining the << operator (operator<<) to work directly with strings is more elegant than having to work with ostringstreams and then converting back to strings. Is there a reason why c++ doesn't do this out of the box?
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
template <class T>
string& operator<<(string& s, T a) {
ostringstream ss;
ss << a;
s.append(ss.str());
return s;
}
int main() {
string s;
// this prints out: "inserting text and a number(1)"
cout << (s << "inserting text and a number (" << 1 << ")\n");
// normal way
ostringstream os;
os << "inserting text and a number(" << 1 << ")\n";
cout << os.str();
}
Streams contain additional state. Imagine if this were possible:
std::string str;
int n = 1234;
str << std::hex;
str << n;
return str; // returns "0x4d2" (or something, I forget)
In order to maintain this additional state, strings would have to have storage for this state. The C++ standards committee (and C++ programmers in general) have generally frowned upon superfluous resource consumption, under the motto "pay only for what you use". So, no extra fields in the string class.
The subjective answer: is that I think the std::string class was quite poorly designed to begin with, especially compared to other parts of C++'s excellent standard library, and adding features to std::string is just going to make things worse. This is a very subjective opinion and feel free to dismiss me as a raving lunatic.
The problem with the idea of strings being output streams is that they would become too heavy.
Strings are intended to "hold string data", not to format some output. Output streams have a heavy "state" which can be manipulated (see <iomanip>) and thus has to be stored. This means that, of course, this has to be stored for every string in every program, but almost none of them are used as an output stream; so it's a huge waste of resources.
C++ follows the "zero overhead" design principle (or at least no more overhead than totally necessary). Not having a string class which doesn't add any unnecessary overhead would be a huge violation of this design principle. If this was the case: what would people do in overhead-critical cases? Use C-strings... ouch!
In C++11, an alternative is to use the operator+= with std::to_string to append to a string, which can also be chained like the operator<< of the output stream. You can wrap both += and to_string in a nice operator<< for string if you like:
template <class Number>
std::string& operator<<(std::string& s, Number a) {
return s += std::to_string(a);
}
std::string& operator<<(std::string& s, const char* a) {
return s += a;
}
std::string& operator<<(std::string& s, const std::string &a) {
return s += a;
}
Your example, updated using this method: http://ideone.com/4zbVtD
Probably lost in the depths of time now but formatted output was always associated with streams in C (since they didn't have "real" strings) and this may have been carried over into C++ (which was, after all, C with classes). In C, the way to format to a string is to use sprintf, a variation on fprintf, the output-to-stream function.
Obviously conjecture on my part but someone probably thought similarly to yourself that these formatting things in the streams would be brilliant to have on strings as well, so they subclassed the stream classes to produce one that used a string as it's "output".
That seems the elegant solution to getting it working as quickly as possible. Otherwise, you would have had formatting code duplicated in streams and strings.
When should I use stringstream instead of string::append()?
Supposing I'm going to catenate just strings.
stringstream ss;
ss << str1 << "str2" << ...
Write(ss.str());
Or:
string str;
str.reserve(10000);
str.append(str1);
str.append("str2");
...
Write(str);
Which of them is faster?
I don't know which one will be faster, but if I had to guess I'd say your second example is, especially since you've called the reserve member function to allocate a large space for expansion.
If you're only concatenating strings use string::append (or string::operator+=).
If you're going to convert numbers to their string representation, as well as format them during conversion, and then append the conversion results together, use stringstreams. I mention the formatting part explicitly because if you do not require formatting C++11 offers std::to_string which can be used to convert numeric types to strings.
string.append is much faster. Especially when you reserve.
If you are concatenating only strings, I would use string.append. I would only use stringstream when I need to automatically convert non-strings to strings for example:
const int x(42);
stringstream ss;
ss << "My favorite number is: " << x << std::endl;
Here stringstream automatically converts x to a string and appends it. I do not need to call atoi. Stringstream will convert all the basic types automatically for you. It is great for that purpose.
Also if you are only going to be directing data into the stringstream to convert it to a string later. You can use ostringstream which is for output.
I hope that helps.