SWIG Python and C++ std::string null-termination problem [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How Python can get binary data(char*) from C++ by SWIG?
I have a SWIG based C++ interface that can called from Python. There is a function in it, that has one std::string argument. It looks like this:
WrapperGet(const std::string& key);
If it is called from Python with a string argument that contains NUL character (e.g. binary data), then the std::string is truncated at the NUL character, and that is my problem, because it makes impossible to handle binary data.
What makes it interesting is that other way works perfectly:
std::string WrapperResult();
The string returned here can contain binary data without truncation. Has anybody any idea what has to be done?
UPDATE: I debugged the SWIG generated code and it turned out that the error was in the wrapper code on the C++ size: it used the c_str() member function of the std::string to get the string value.
Thanks for everybody's ideas and time!

I've had to deal with this in the past, and I just grabbed the std::string conversion template from SWIG and tailored it a bit to use PyString_FromStringAndSize when creating a Python string from a std::string and the std::string constructor that accepts a size argument when going the other way.
That was with a really old version of SWIG, though - I thought the builtin conversion template in newer versions had been updated to do that automatically. Is it possible the problem is on the C++ side? (e.g. as in Mark Tolonen's examples, where the first example is truncated due to the embedded NULL in the constructor call without a size argument).

It is probably how the strings are constructed. Consider:
string blah(const string& x)
{
string y("abc\x00def");
return x + y;
}
string blah2(const string& x)
{
string y("abc\x00def",7);
return x + y;
}
Calling these from Python:
>>> import x
>>> x.blah('abc\x00def')
'abc\x00defabc'
>>> x.blah2('abc\x00def')
'abc\x00defabc\x00xyz'
The constructor for std::string(const char*) stops at the NULL, but clearly SWIG can pass in and return strings with a NULL in them.

Related

How to convert opcua string to standard string in c++

can someone tell how to convert UaString to std::string in c++.
There is already a question which converts std::string to uastring:
How can i convert a std::string to UaString?
Thanks in advance!
e.g. You have UaString as below:
UaString sString("Test String");
Then you can make standard string as,
std::string myString(sString.toUtf8());
Reference:
UA Server SDK C++
C++ String Class
One way could be to use the toUtf8 member function which returns a const char* that can be used to construct a std::string.
std::string str(uastring.toUtf8());
An alternative if uastring may contain null terminators:
std::string str(uastring.toUtf8(), uastring.size());
Note that UaString::length() shouldn't be used in this case since it returns the number of UTF8 characters while UaString::size() returns the number of bytes (which may be greater).

How can I send a struct of arrays into a function when using the String object?

I'm learning to code c++ and I've come to this problem:
I have this struct:
struct storeData
{
string name;
string username;
string fav_food;
string fav_color;
}data[30];
And I need to check if two usernames are equal so I made this statement:
for(i=0;i<c;i++){
if(data[c].username.compare(data[i].username)==0){
cout<<"Username already taken"<<endl;
}
}
And it works well, the problem that I have is that I'm required to make a function let's call it: isTaken that returns the error message, so I can use it whenever I need to for example delete a username so I don't have to copy/paste the code again.
So I began looking for an answer for that, many forums present a way to send the whole struct like this:
void isTaken(struct storeData *data)
which I understand but because I'm using string is not working, so I guess it's because string is an object? I'm using the library <string> I'm sorry if I'm not being that clear at the moment, I'm looking for a way to use isTaken(data[c].user); but I don't know how to declare the function, I think is also because string is not the same as C string but I'm not really sure I've been looking for a solution and could not find it.
I tried: void isTaken(struct storeData *data) but I got an error saying that I can't convert std::string to basic_string which makes sense if I'm correct about string I tried converting string into c string but could not get anywhere. I'm open to suggestions/corrections because I want to improve my code, also I could not find the answer here, so If someone's got a link to a problem like this please let me know.
Thank you so much for you time, have a good day.
Do you mean an array of structs instead of a struct of arrays?
In the example you are giving I see only an array of structs each of which has multiple string objects in it. You see, a string is a class coming from std and I wouldn't call it an array. If you want to know how to pass an array to a function, you should read about it (I'm sure you can find such a question in SO). If you want to have an array within your struct, then the struct will take care of the memory of the array, but you should definitely read about constructors.
You got an error because you are passing an string argument to a function which requires struct pointer
void isTaken(struct storeData *data);
...
isTaken(data[c].user);
but what you actually need is to have a function which takes an array of your users, its size and username you want to check
bool IsUsernameTaken(struct storeData data[], int dataSize, const string &username){
for(int i = 0; i<dataSize; i++){
if(username == data[i].username)
return true;
}
return false;
}
A C string looks like this
data
A C++ string usually looks like this
size
capacity
ptr
|
v
data
or if using short string optimization and the string is short enough
size
data
data
all are zero terminated.
Making a shallow copy a C string only cost the copy of the pointer to it. Where a copy of a might cost just copying the 3 members and possible an allocation of data, which is not ideal, therefor most C++ functions use a reference to a string making the cost equivalent to the C string.
All code is untested.
bool Find(const std::string& target);
Making a deep copy of a C string would also cost an allocation.
In C++ you have many options to do a search, for your struct it could look like this. In case your member variables are private you must use an access function
auto found = std::find(std::begin(data), std::begin(data)+c, [&target](const storeData& auser) { return auser.GetName() == target });
return (found != std::begin(data)+c);
The first two parameters are the range that is search, not including the 2nd. A lambda is used to check the name, a free function with the right declaration would also do.
std::string& GetName() { return name; }
The higher C++ protection schemes would advice adding 2 consts to that in case you don't need to change name.
const std::string& GetName() const { return name; }
Meaning the returned string cant be changed and the 2nd says it wont change anything in your class. This const version would be required as I used a const storeData& auser in the lambda to satisfy the constness of the struct.

MoveFileA() doesn't like my arguments [duplicate]

This question already has answers here:
How to convert std::string to LPCSTR?
(9 answers)
Closed 8 years ago.
I have a list of file names in a .txt document, and I would like to move each of these files from one folder to another.
Using MoveFileA() I am getting the error, "no suitable conversion between std::string and LCPSTR".
Here is my code, after opening up my .txt file:
while (std::getline(myfile, line))
{
std::string oldLocation = "C:\\Users\\name\\Desktop\\docs\\folder1\\" + line;
std::string newLocation = "C:\\Users\\name\\Desktop\\docs\\folder2\\" + line;
MoveFileA(oldLocation, newLocation);
}
If I type in the full path as arguments for MoveFileA, instead of sending it a variable, it works but I am unable to iterate over .txt file this way.
Any suggestions on how I might fix this?
LCPSTR means long constant pointer to a string, which means it's a null terminated c string.
std::string is an object. It is something different. But it luckily provides a convenience method c_str the provides a pointer to a constant c style string. So as the comment says you should go by:
MoveFileA(oldLocation.c_str(), newLocation.c_str());
It is worth of explicitly noting, that you can't drop it in every place instead of char*, but only when the string won't be modified. It returns const char*. This is where the C in LCPSTR gets important.

Conversion problems in C++ (string expected)

I have a function that I cannot touch, Is a "log maker", It puts something to print in a file an show it up when I run the file. The problem is that the function only gets const string so if I want to print something I have to convert everything in this data type (I cannot use cout).
itoa & atoi functions are not standard functions so I cannot use it neither. C++ is very "special" with data types and doesn't accept conversions really easy, so this is my question:
How can I convert everytype of data into string for the log purposes?
Probably I should check data type on a function to convert things and returning them into a stringstream (witch I have to convert into a string, of course).
So, any advice on how to do that?
boost::lexical_cast encapsulates the use of ostringstream, so you
could use that. Otherwise, the code isn't that difficult:
template<typename T>
std::string
toString( T const& object )
{
std::ostringstream results;
results << object;
return results.str();
}
(There's no reason to use stringstream here; ostringstream is largely sufficient.
You can use
std::stringstream
or
boost lexical_cast<>
Yes, if you want arbitrary type in string representation stringstream intermediate sounds like a solution.
I assume the functions expects a const std::string & ?
Your approach with std::stringstream is correct. Alternatively you could simply write a toString() method for the class you wish to directly output. However, usually when one wants to output objects to a file, overloads the << operator for that particular type.

Char to Int in C++? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to convert a single char into an int
Well, I'm doing a basic program, wich handles some input like:
2+2
So, I need to add 2 + 2.
I did something like:
string mys "2+2";
fir = mys[0];
sec = mys[2];
But now I want to add "fir" to "sec", so I need to convert them to Int.
I tried "int(fir)" but didn't worked.
There are mulitple ways of converting a string to an int.
Solution 1: Using Legacy C functionality
int main()
{
//char hello[5];
//hello = "12345"; --->This wont compile
char hello[] = "12345";
Printf("My number is: %d", atoi(hello));
return 0;
}
Solution 2: Using lexical_cast(Most Appropriate & simplest)
int x = boost::lexical_cast<int>("12345");
Solution 3: Using C++ Streams
std::string hello("123");
std::stringstream str(hello);
int x;
str >> x;
if (!str)
{
// The conversion failed.
}
Alright so first a little backround on why what you attempted didn't work. In your example, fir is declared as a string. When you attempted to do int(fir), which is the same as (int)fir, you attempted a c-style cast from a string to an integer. Essentially you will get garbage because a c-style cast in c++ will run through all of the available casts and take the first one that works. At best your going to get the memory value that represents the character 2, which is dependent upon the character encoding your using (UTF-8, ascii etc...). For instance, if fir contained "2", then you might possibly get 0x32 as your integer value (assuming ascii). You should really never use c-style casts, and the only place where it's really safe to use them are conversions between numeric types.
If your given a string like the one in your example, first you should separate the string into the relevant sequences of characters (tokens) using a function like strtok. In this simple example that would be "2", "+" and "2". Once you've done that you can simple call a function such as atoi on the strings you want converted to integers.
Example:
string str = "2";
int i = atoi(str.c_str()); //value of 2
However, this will get slightly more complicated if you want to be able to handle non-integer numbers as well. In that case, your best bet is to separate on the operand (+ - / * etc), and then do a find on the numeric strings for a decimal point. If you find one you can treat it as a double and use the function atof instead of atoi, and if you don't, just stick with atoi.
Have you tried atoi or boost lexical cast?