QString to C string -> Fortran
-
I have a strange problem that may be created by my lack of C/C++ skills.
Starting from QStrings, I create two C strings that are passed to a Fortran subroutine. On my Windows 7 machine this works fine - almost all the time. But on a colleagues Windows 10 machine the strings are corrupted every time.
Here is the declaration of the Fortran subroutine, in a DLL:
void execute(int *,char *, int *,char *, int *, int *);Here is the summary of what I'm doing in the Qt code:
QString qsrt1, qstr2;
char *cstr1, *cstr2;
...
QByteArray ba = qstr1.toLocal8Bit();
cstr1 = ba.data();
ba = qstr2.toLocal8Bit();
cstr2 = ba.data();
...
execute(&ncpu,str1,&len1,str2,&len2,&res);The Fortran code is correct, but on one machine the strings str1 and str2 appear as non-printing characters - random memory, I suspect.
What makes it very hard to debug is the fact that I almost never see the problem on my old W7 system; I thought it never happened, but then after running the program more than 20 times I got the corrupted string error. There is always the possibility that the problem is elsewhere in the Qt code, but I want to check that I'm not making a mistake with the string conversion. One question is whether I should be using const char * rather than char *.Thanks.
-
I have a strange problem that may be created by my lack of C/C++ skills.
Starting from QStrings, I create two C strings that are passed to a Fortran subroutine. On my Windows 7 machine this works fine - almost all the time. But on a colleagues Windows 10 machine the strings are corrupted every time.
Here is the declaration of the Fortran subroutine, in a DLL:
void execute(int *,char *, int *,char *, int *, int *);Here is the summary of what I'm doing in the Qt code:
QString qsrt1, qstr2;
char *cstr1, *cstr2;
...
QByteArray ba = qstr1.toLocal8Bit();
cstr1 = ba.data();
ba = qstr2.toLocal8Bit();
cstr2 = ba.data();
...
execute(&ncpu,str1,&len1,str2,&len2,&res);The Fortran code is correct, but on one machine the strings str1 and str2 appear as non-printing characters - random memory, I suspect.
What makes it very hard to debug is the fact that I almost never see the problem on my old W7 system; I thought it never happened, but then after running the program more than 20 times I got the corrupted string error. There is always the possibility that the problem is elsewhere in the Qt code, but I want to check that I'm not making a mistake with the string conversion. One question is whether I should be using const char * rather than char *.Thanks.
-
IMHO the safe way to do that can be:
- Convert the strings as you mentioned in your code above.
- Allocate memory for your string like below:
char *str = new char[qbytearray.size()+1]; strcpy(str, qbytearray.constData());
- Than call your Fortran function.
- Delete the allocated buffers after the Fortran function was executed (delete[] str).
-
IMHO the safe way to do that can be:
- Convert the strings as you mentioned in your code above.
- Allocate memory for your string like below:
char *str = new char[qbytearray.size()+1]; strcpy(str, qbytearray.constData());
- Than call your Fortran function.
- Delete the allocated buffers after the Fortran function was executed (delete[] str).
@ad1170 said in QString to C string -> Fortran:
IMHO the safe way to do that can be:
QByteArray is much better since you can't forget the deallocation...
-
IMHO the safe way to do that can be:
- Convert the strings as you mentioned in your code above.
- Allocate memory for your string like below:
char *str = new char[qbytearray.size()+1]; strcpy(str, qbytearray.constData());
- Than call your Fortran function.
- Delete the allocated buffers after the Fortran function was executed (delete[] str).
-
I have a strange problem that may be created by my lack of C/C++ skills.
Starting from QStrings, I create two C strings that are passed to a Fortran subroutine. On my Windows 7 machine this works fine - almost all the time. But on a colleagues Windows 10 machine the strings are corrupted every time.
Here is the declaration of the Fortran subroutine, in a DLL:
void execute(int *,char *, int *,char *, int *, int *);Here is the summary of what I'm doing in the Qt code:
QString qsrt1, qstr2;
char *cstr1, *cstr2;
...
QByteArray ba = qstr1.toLocal8Bit();
cstr1 = ba.data();
ba = qstr2.toLocal8Bit();
cstr2 = ba.data();
...
execute(&ncpu,str1,&len1,str2,&len2,&res);The Fortran code is correct, but on one machine the strings str1 and str2 appear as non-printing characters - random memory, I suspect.
What makes it very hard to debug is the fact that I almost never see the problem on my old W7 system; I thought it never happened, but then after running the program more than 20 times I got the corrupted string error. There is always the possibility that the problem is elsewhere in the Qt code, but I want to check that I'm not making a mistake with the string conversion. One question is whether I should be using const char * rather than char *.Thanks.
@gibbogle said in QString to C string -> Fortran:
Starting from QStrings, I create two C strings that are passed to a Fortran subroutine. On my Windows 7 machine this works fine - almost all the time. But on a colleagues Windows 10 machine the strings are corrupted every time.
Here is the declaration of the Fortran subroutine, in a DLL:
void execute(int *,char *, int *,char *, int *, int *);Here is the summary of what I'm doing in the Qt code:
QString qsrt1, qstr2;
char *cstr1, *cstr2;
...
QByteArray ba = qstr1.toLocal8Bit();If this string contains any characters that cannot be encoded in the locale, the returned byte array is undefined. Those characters may be suppressed or replaced by another.
Do the locales or QString contents differ between the two machines?
cstr1 = ba.data(); ba = qstr2.toLocal8Bit(); cstr2 = ba.data(); ... execute(&ncpu,str1,&len1,str2,&len2,&res);
The pointer remains valid as long as the byte array isn't reallocated or destroyed
cstr1 becomes an unsafe pointer when ba is overwritten with the return value of qstr2.toLocal8Bit(). @koahnig's suggestion to use a QByteArray per QString should fix this.
One question is whether I should be using const char * rather than char *.
It's not a bad idea. There's also QByteArray::constData()
-
@ad1170 In addition to @Christian-Ehrlicher - you don't need +1 to the size() of QByteArray as this method already returns +1 for \0 char. And yes, QByteArray is much, much safer.
@artwaw said in QString to C string -> Fortran:
@ad1170 In addition to @Christian-Ehrlicher - you don't need +1 to the size() of QByteArray as this method already returns +1 for \0 char.
Although I see @kshegunov & @SGaist have up-voted this, you're all wrong! :) You have to read https://doc.qt.io/qt-5/qbytearray.html#size carefully. Although it is true that
QByteArray
(usually) adds a\0
at the end of the byte array, it adds at indexbyteArray[byteArray.size()]
, i.e. 1 beyond the length returned byQByteArray::size()
:The last byte in the byte array is at position size() - 1. In addition, QByteArray ensures that the byte at position size() is always '\0', so that you can use the return value of data() and constData() as arguments to functions that expect '\0'-terminated strings
QByteArray::size()
returns the length without the extra terminating\0
. That means that to copy it as a string you must indeed allocatechar *str = new char[qbytearray.size()+1];
as @ad1170 did. If you don't do the+ 1
then thestrcpy()
will copy the terminating\0
to 1 byte beyond the allocated area, leading to potential nasties...! -
@artwaw said in QString to C string -> Fortran:
@ad1170 In addition to @Christian-Ehrlicher - you don't need +1 to the size() of QByteArray as this method already returns +1 for \0 char.
Although I see @kshegunov & @SGaist have up-voted this, you're all wrong! :) You have to read https://doc.qt.io/qt-5/qbytearray.html#size carefully. Although it is true that
QByteArray
(usually) adds a\0
at the end of the byte array, it adds at indexbyteArray[byteArray.size()]
, i.e. 1 beyond the length returned byQByteArray::size()
:The last byte in the byte array is at position size() - 1. In addition, QByteArray ensures that the byte at position size() is always '\0', so that you can use the return value of data() and constData() as arguments to functions that expect '\0'-terminated strings
QByteArray::size()
returns the length without the extra terminating\0
. That means that to copy it as a string you must indeed allocatechar *str = new char[qbytearray.size()+1];
as @ad1170 did. If you don't do the+ 1
then thestrcpy()
will copy the terminating\0
to 1 byte beyond the allocated area, leading to potential nasties...!@JonB You're right. For new/malloc and strcpy the additional \0 has to be considered.
-
@ad1170 said in QString to C string -> Fortran:
IMHO the safe way to do that can be:
QByteArray is much better since you can't forget the deallocation...
@Christian-Ehrlicher said in QString to C string -> Fortran:
@ad1170 said in QString to C string -> Fortran:
IMHO the safe way to do that can be:
QByteArray is much better since you can't forget the deallocation...
You are right. Inside Qt, use QByteArray or QString, no question.
But calling a function with an other language binding or from an other library which is awaiting char *str or const char *str i would prefer to make sure that the function gets what she wants. A plain C convention string with a trailing \0. -
@ad1170 said in QString to C string -> Fortran:
But calling a function with an other language binding or from an other library which is awaiting char *str or const char *str i would prefer to make sure that the function gets what she wants.
It wantsa char*, it gets one - QByteArray::data() returns a pointer to a char array... it simply useless and error prone (e.g. forgot to call delete) what you suggest.
-
@koahnig According to my colleague, the program is now working - your fix was successful.. Thanks.