I have my own class that represents a custom string class. I'm using VS2012RC. I have overloaded some operators of my class CustomString.
Here's some code:
CustomString::CustomString(string setstr)
{
str = setstr;
}
CustomString::operator const char *()
{
return (this->str.c_str());
}
CustomString &CustomString::operator = (char *setstr)
{
str = setstr;
return *this;
}
I can define my object and use it like this:
CustomString str = "Test string";
and i can print the result as:
printf(str);
printf((string)(str).c_str());
printf((string)(str).data());
printf("%s\n",(string)(str).c_str());
printf("%s\n",(string)(str).data());
And there is not any error.
But if i use it like this:
printf("%s\n", str);
There is an exception in msvcr110d.dll (error in memory access)
Why printf(str) is ok, but printf("%s\n",str) is not ok?
How can i modify my code to use printf("%s\n",str) ?
...
After hours of googling, I found that explict cast (string), static_cast (str) and _str() method are add a null-terminated chars: '\0';
i've modified my code as:
printf("%s\n",str + '\0');
and it's worked!
Is there any way to modify my custom constructor to add a null-terminated string and pass a correct value with null-terminated chars to get working the following code:
printf("%s\n",str);
Don't use printf, its more C-like than C++. Instead, use iostreams, which provide a facility for you to format your own custom classes and send the to a file or stdout.
Here's a quick (untested) example that might work for you:
std::ostream& operator<< (std::ostream &os, const CustomString& str)
{
os << str.data();
return os;
}
and you'd print your custom string to stdout by doing something like
CustomString str;
// put some text in the custom string, then:
std::cout << str << std::endl;
You can't (at least not in a portable way). printf looks at the object passed as parameter and treats it as a %s, which is a char array. You run into undefined behavior. Also, the parameters passed to printf are, sort of say, type-less.
Why printf(str) is ok?
Because the first parameter is types, and is a const char*. The implicit cast is made via your operator. The rest of the parameters don't behave the same.
I'd use cout instead, and overload operator << (ostream&, const CustomString&).
Don't do this:
I said you can't, in a portable way. For a class like
class CustomString
{
char* str;
//...
};
that might work, because of how classes are represented in memory. But, again, it's still undefined behavior.
printf is defined as
int printf(char const *fmt, ...)
passing a class or structure to a ... argument list has undefined behaviour and may work or crash, or just do something random (I've seen all 3) depending on the class and the compiler.
printf(str)
requires a char *, and the compiler finds you have an appropriate casting operator, so it invokes it. Note that this is pretty dodgy as you have no idea if str might or might not have a % in it.
So, you to do want printf("%s", str) but as you have said, that doesn't work. Some compilers will give you a warning (though 'warning: This will crash' as produced by gcc isn't, in my opinion, terribly well thought out), so you have to force it to be cast to a string. So, your best solution is to explicitly cast it yourself,
printf("%s", static_cast<char const *>(str));
I'm not sure how much code all of the examples you've got there would require, as most of them are going to involve constructing a std::string from your custom string, then outputting it, then deleting the std::string.
You have to use printf("%s\n", str.c_str());. %s expects a char array and you gave it a CustomString object which is something different. You have to get char array from the string by calling c_str() function.
Related
This question already has answers here:
What is the difference between these two cases of adding a string?
(5 answers)
Closed 7 years ago.
I have a function like this
void foo (const char* myString){
...
}
and I want to use it like this
std::string tail = "something";
foo("my" + "string" + tail);
But I just can't find an easy way. For sure I can make the string somewhere else and pass it to foo(). But I prefer to find a way to do it inline, because foo() is called several times in the code, I don't want to make a string for each time. I tried
foo(std::string ("my" + "string" + tail).c_str())
but you can guess that it doesn't work.
"my"and "string" are C style string literals, which have the odd rule that they will be concatenated if they are written without a +.
So "my" "string" + tail will work, and produce a std::string. However, it will still not be the correct type for your function, unless you use .c_str() on the result.
"my" and "string" are C-style strings. Their types are const char *, you cannot use operator + for these operands. But you can use this operator is any of the operands is string.
So the most elegant way for you it to add parenthesis:
foo(("my" + ("string" + tail)).c_str());
You will also have to change function foo to
void foo (const char* myString)
Just make sure "my" is a std::string, then you can use the std::string::operator+ operator on it. Later you use .c_str() on the resulting std::string.
Then, if you can change foo, the best is to make it accept const char*:
void foo (const char* myString)
{
...
}
std::string tail = "something";
foo( (std::string("my") + "string" + tail).c_str() );
If you can't change foo, then you'll have to do a cast because c_str() returns a const char* and foo wants a char*:
void foo (char* myString)
{
...
}
std::string tail = "something";
foo( const_cast<char*>( (std::string("my") + "string" + tail).c_str() ) );
Your function accepts a modifiable array (not anymore, OP changed that in an edit) of char and std::string is not an array of char, but some unrelated object (that provides read-access to its internal char buffer, but that does not make it some kind of pretty array).
Additionally, using .c_str()-pointers into destroyed string objects is a common bug. Even if your function was to accept a const char* instead, you need to be aware that the pointer passed into it would only be valid until the end of the full expression the temporary std::string object was created in. This might or might not be what you want here, but is something you really need to watch out for. As I said, people get it wrong quite often.
So std::string probably (in the new const char* setting, it might) is not the right tool for this job as it is described right now.
The best solution would be to make the argument of foo() an std::string (of some reference variant, depending on what it is doing). Then you can concatenate the inputs with + as long as one of the first summands already is an std::string.
If this should not be possible, copy the characters into an std::vector<char> which actually is the C++ way to get a char array (again, unlike string).
The code foo("my" + "string" + tail); does not work for two reasons. First is order of operators. The code tries to execute "my" + "string", and since both of those are string literals, code fails. (you can not add up two string literals). The first issue is that if you magically make "my" + "string" working, code will concatenate it with tail, produce valid std::string, but fail to pass it to foo().
How to fix the issue?
Change foo() signature. make it foo(const char* ) if you have to use char*, or, better, replace it with foo(const std::string&).
Use following to concatenate: foo(std::string("my") + "string" + tail) if you followed my advice and made foo accepting const std::string&, or foo((std::string("my") + "string" + tail).c_str()) if you did not.
On a side note, since both "my" and "string" are known at compile time, it's better to have simple foo("mystring" + tail) - easier to read, better performance.
I have been working with C++ strings and trying to load char * strings into std::string by using C functions such as strcpy(). Since strcpy() takes char * as a parameter, I have to cast it which goes something like this:
std::string destination;
unsigned char *source;
strcpy((char*)destination.c_str(), (char*)source);
The code works fine and when I run the program in a debugger, the value of *source is stored in destination, but for some odd reason it won't print out with the statement
std::cout << destination;
I noticed that if I use
std::cout << destination.c_str();
The value prints out correctly and all is well. Why does this happen? Is there a better method of copying an unsigned char* or char* into a std::string (stringstreams?) This seems to only happen when I specify the string as foo.c_str() in a copying operation.
Edit: To answer the question "why would you do this?", I am using strcpy() as a plain example. There are other times that it's more complex than assignment. For example, having to copy only X amount of string A into string B using strncpy() or passing a std::string to a function from a C library that takes a char * as a parameter for a buffer.
Here's what you want
std::string destination = source;
What you're doing is wrong on so many levels... you're writing over the inner representation of a std::string... I mean... not cool man... it's much more complex than that, arrays being resized, read-only memory... the works.
This is not a good idea at all for two reasons:
destination.c_str() is a const pointer and casting away it's const and writing to it is undefined behavior.
You haven't set the size of the string, meaning that it won't even necessealy have a large enough buffer to hold the string which is likely to cause an access violation.
std::string has a constructor which allows it to be constructed from a char* so simply write:
std::string destination = source
Well what you are doing is undefined behavior. Your c_str() returns a const char * and is not meant to be assigned to. Why not use the defined constructor or assignment operator.
std::string defines an implicit conversion from const char* to std::string... so use that.
You decided to cast away an error as c_str() returns a const char*, i.e., it does not allow for writing to its underlying buffer. You did everything you could to get around that and it didn't work (you shouldn't be surprised at this).
c_str() returns a const char* for good reason. You have no idea if this pointer points to the string's underlying buffer. You have no idea if this pointer points to a memory block large enough to hold your new string. The library is using its interface to tell you exactly how the return value of c_str() should be used and you're ignoring that completely.
Do not do what you are doing!!!
I repeat!
DO NOT DO WHAT YOU ARE DOING!!!
That it seems to sort of work when you do some weird things is a consequence of how the string class was implemented. You are almost certainly writing in memory you shouldn't be and a bunch of other bogus stuff.
When you need to interact with a C function that writes to a buffer there's two basic methods:
std::string read_from_sock(int sock) {
char buffer[1024] = "";
int recv = read(sock, buffer, 1024);
if (recv > 0) {
return std::string(buffer, buffer + recv);
}
return std::string();
}
Or you might try the peek method:
std::string read_from_sock(int sock) {
int recv = read(sock, 0, 0, MSG_PEEK);
if (recv > 0) {
std::vector<char> buf(recv);
recv = read(sock, &buf[0], recv, 0);
return std::string(buf.begin(), buf.end());
}
return std::string();
}
Of course, these are not very robust versions...but they illustrate the point.
First you should note that the value returned by c_str is a const char* and must not be modified. Actually it even does not have to point to the internal buffer of string.
In response to your edit:
having to copy only X amount of string A into string B using strncpy()
If string A is a char array, and string B is std::string, and strlen(A) >= X, then you can do this:
B.assign(A, A + X);
passing a std::string to a function from a C library that takes a char
* as a parameter for a buffer
If the parameter is actually const char *, you can use c_str() for that. But if it is just plain char *, and you are using a C++11 compliant compiler, then you can do the following:
c_function(&B[0]);
However, you need to ensure that there is room in the string for the data(same as if you were using a plain c-string), which you can do with a call to the resize() function. If the function writes an unspecified amount of characters to the string as a null-terminated c-string, then you will probably want to truncate the string afterward, like this:
B.resize(B.find('\0'));
The reason you can safely do this in a C++11 compiler and not a C++03 compiler is that in C++03, strings were not guaranteed by the standard to be contiguous, but in C++11, they are. If you want the guarantee in C++03, then you can use std::vector<char> instead.
I am well aware of techniques to convert CString to a C-style character. One of them is to use strcpy/_tcscpy, and others include using CStrBuf.
The problem:
char Destination[100];
CStringA Source; // A is for simplicity and explicit ANSI specification.
Source = "This is source string."
Now I want this:
Destination = Source;
To happen automatically. Well, that logically means writing a conversion operator in CString class. But, as implicit as it is, I dont have privileges to change the CString class.
I thought of writing a global conversion opertor and global assignment operator. But it doesnt work:
operator char* (const CStringA&); // Error - At least must be class-type
operator = ... // Won't work either - cannot be global.
Yes, it is definitely possible to write function (preferably a templated one). But that involves calling the function, and it is not smooth as assignment operator.
You cannot assign to arrays. This makes what you want impossible. Also, honestly, it's a pretty wrong thing to do - a magic-number-sized buffer?
Well, I don't want to say that this is in any way recommendable, but you could hijack some lesser-used operator for a quick hack:
void operator<<=(char * dst, const std::string & s)
{
std::strcpy(dst, s.c_str());
}
int main()
{
char buf[100];
std::string s = "Hello";
buf <<= s;
}
You could even rig up a moderately safe templated version for statically sized arrays:
template <typename TChar, unsigned int N>
inline void operator<<=(TChar (&dst)[N], const std::string & s)
{
std::strncpy(dst, s.c_str(), N);
}
An operator on CString won't solve the problem since you need to copy to Destination buffer although this assignment would change the value of Destination, which is impossible.
Somehow, you need an operator to achive this line:
strcpy(Destination, LPCSTR(Source)); // + buffer overflow protection
As you can see, converting Source is only half way. You still need to copy to the destination buffer.
Also, I wouldn't recommend it because the line Destination = Source is completely misleading in regard of the char[] semantics.
The only possible such assignment would be an initialisation of Destination:
char Destination[100] = Source;
I have char* which is of fixed (known) width but is not null terminated.
I want to pass it into LOG4CPLUS_ERROR("Bad string " << char_pointer); but as its not null terminated it will print it all.
Any suggestions of some light weight way of getting "(char[length])*char_pointer" without performing a copy?
No, you'll have to deep-copy and null-terminate it. That code expects a null-terminated string and it means a contiguous block of characters ending with a null terminator.
If your goal is to print such a string, you could:
Store the last byte.
Replace it with \0.
Print the string.
Print the stored byte.
Put the stored byte back into the last position of the string.
Wrap all this in a function.
Real iostreams
When you're writing to a real iostream, then you can just use ostream.write() which takes a char* and a size for how many bytes to write -- no null termination necessary. (In fact, any null characters in the string would be written to the ostream, and would not be used to determine the size.)
Logging libraries
In some logging libraries, the stream that you write to is not a real iostream. This is the case in Log4CPP.
However, in Log4CPlus which is what it appears matt is using, the object that you're writing to is a std::basic_ostringstream<tchar> (see loggingmacros.h and streams.h for the definition, since none of this is obvious from the documentation). There's just one problem: in the macro LOG4CPLUS_ERROR, the first << is already built into the macro, so he won't be able to call LOG4CPLUS_ERROR(.write(char_pointer,length)) or anything like that. Unfortunately, I don't see an easy way around this without deconstructing the LOG4CPLUS_ERROR error macro and getting into the internals of Log4CPlus
Solution
I'm not sure why you're trying to avoid copying the string at this point, since you can see that there's a lot of copying going on inside the logging library. Any attempt to avoid that extra string copy is probably unwarranted optimization.
I'm going to assume that it's an issue of code cleanliness, and maybe an issue of making sure the copy happens inside the LOG4CPLUS_ERROR macro, as opposed to outside it. In that case, just use:
LOG4CPLUS_ERROR("Bad string " << std::string(char_pointer, length));
We're getting hung up on the semantics of conversion between char* and char[]. Take a step back, what are you trying to do? If this is a simple case of on an error condition, streaming out the content of a structure to a stream, why not do it properly?
e.g.
struct foo
{
char a1[10];
char a2[10];
char a3[10];
char a4[10];
};
// free function to stream the above structure properly..
std::ostream operator<<(std::ostream& str, foo const& st)
{
str << "foo::a1[";
std::copy(st.a1, st.a1 + sizeof(st.a1), std::ostream_iterator<char>(str));
str << "]\n";
str << "foo::a2[";
std::copy(st.a2, st.a2 + sizeof(st.a2), std::ostream_iterator<char>(str));
str << "]\n";
:
return str;
}
Now you can simply stream out an instance of foo and don't have to worry about null terminated string etc.!
I keep a string reference class in my toolkit just for these type of situations. Here is a greatly abbreviated version of that class. I trimmed away anything that is not relevant to this particular problem:
#include <iostream>
class stringref {
public:
stringref(const char* ptr, unsigned len) : ptr(ptr), len(len) {}
unsigned length() { return len; }
const char* data() { return ptr; }
private:
const char* ptr;
unsigned len;
};
std::ostream& operator<< (std::ostream& os, stringref sr) {
const char* data = sr.data();
for (unsigned len = sr.length(); len--; )
os << *data++;
return os;
}
using namespace std;
int main (int argc, const char * argv[])
{
cout << "string: " << stringref("test", 4) << endl;
}
or, in your case:
LOG4CPLUS_ERROR("Bad string " << stringref(char_pointer, length));
should work.
The idea of a string reference class is to keep enough information about a string (a size and a pointer) to refer to any block of memory which represents a string. It relies on you to make sure that the underlying string data is valid throughout the lifetime of a stringref object. This way you can pass around and process string information with a minimum of overhead.
When you know it is of fixed length: Why not simply add one more charakter to the size of the array? Then you can easily fill this last char with \0 terminating character and all will be fine
No, you'll have to copy it. There is no proper conversion in the language that you can use to get the array type out of it.
It seems very odd that you want to do this, or that you have a non-terminated C-style string in the first place.
Why are you not using std::string?
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Can I get a non-const C string back from a C++ string?
Do I need to convert it first? I saw in another post that .c_str() can be used if the function expected const char*. What about for just char*?
std::vector<char> buffer(s.begin(), s.end());
foo(&buffer[0], buffer.size());
s.assign(buffer.begin(), buffer.end());
There is no way to get a char* from a string that is guaranteed to work on all platforms, for the simple fact that string is not required to use contiguous storage.
Your safest, most portable course of action is to copy the string somewhere that does use contigious storage (a vector perhaps), and use that instead.
vector<char> chars(my_string.begin(), my_string.end());
char* ptr = &chars[0];
If you want to be hacky and non-portable and decidedly unsafe, you can confirm that your string implementation does in fact use contigious storage, and then maybe use this:
&my_str[0]
But I would punch any developer that worked for me that did this.
EDIT:
I've been made aware that there are currently no known STL implementations that do not store the string data in a contiguous array, which would make &my_str[0] safe. It is also true (and I was asked to state this) that in the upcoming C++0x standard, it will be required for the storage to be contiguous.
It's been suggested that because if these facts that my post is factually incorrect.
Decide for yourself, but I say no. This is not in the current C++ standard, and so it is not required. I will still in practice do things the way I have suggested, and in any code review I will flag any code that assumes the underlying storage is contigious.
Consider this. Suppose there were a question about vtable pointers. Someone wants to examing a class and get the pointer to a virtual function by looking at the vtable. I would immediately tell them not to do this because there is no mention of how virtual methods are implemented in C++. Every implementation I know uses vtables, and I can't think of a better way to do it. It is likely that polymorphism will forever be implemented using vtables. Does that make it ok to examing the vtable directly?
IMO no, because this depends on undocumented implementation details. You have no control over this, and it could change at any time. Even if you expect it will never change, it is still bad engineering to rely on these implementation details.
Decide for yourself.
There are three scenarios:
If the function is outside of your control, and it either modifies the string, or you don't and can't know if it modifies the string:
Then, copy the string into a temporary buffer, and pass that to the function, like so:
void callFoo(std::string& str);
{
char* tmp = new char str(str.length() +1);
strncpy(tmp, str.c_str(), str.length());
foo(tmp);
// Include the following line if you want the modified value:
str = tmp;
delete [] tmp;
}
If the function is outside of your control, but you are certain it does not modify the string, and that not taking the argument as const is simply a mistake on the API's part.
Then, you can cast the const away and pass that to the function
void callFoo(const std::string& str)
{
foo(const_cast<char*> str.c_str());
}
You are in control of the function (and it would not be overly disruptive to change the signature).
In that case, change the function to accept either a string& (if it modifies the input buffer) or either const char* or const string& if it does not.
When a parameter is declared as char* there it is implicitly assumed that the function will have as a side effect the modification of the string that is pointed. Based in this and the fact that c_str() does not allow modifications to the enclosed string you cannot explicitly pass an std::string to such a method.
Something like this can be achived by following the following approach:
#include <cstdlib>
#include <string>
#include <iostream>
void modify_string(char* pz)
{
pz[0] = 'm';
}
class string_wrapper
{
std::string& _s;
char* _psz;
string_wrapper(const string_wrapper&);
string_wrapper& operator=(const string_wrapper&);
public:
string_wrapper(std::string& s) : _s(s), _psz(0) {}
virtual ~string_wrapper()
{
if(0 != _psz)
{
_s = _psz;
delete[] _psz;
}
}
operator char*()
{
_psz = new char[_s.length()+1];
strcpy(_psz,_s.c_str());
return _psz;
}
};
int main(int argc, char** argv)
{
using namespace std;
std::string s("This is a test");
cout << s << endl;
modify_string(string_wrapper(s));
cout << s << endl;
return 0;
}
If you are certain that the char* will not be modified, you can use const_cast to remove the const.
It's a dirty solution but I guess it works
std::string foo("example");
char* cpy = (char*)malloc(foo.size()+1);
memcpy(cpy, foo.c_str(), foo.size()+1);