Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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.



  • @gibbogle

    Make two different QByteArray one for each string and try



  • @koahnig OK, will try. I have to transfer the executable to the colleague in a different time zone (8 hours different), so I will not know the result until she wakes up. Testing on my machine is useless.
    Thanks!



  • IMHO the safe way to do that can be:

    1. Convert the strings as you mentioned in your code above.
    2. Allocate memory for your string like below:
    char *str = new char[qbytearray.size()+1];
    strcpy(str, qbytearray.constData());
    
    1. Than call your Fortran function.
    2. Delete the allocated buffers after the Fortran function was executed (delete[] str).

  • Qt Champions 2019

    @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...



  • @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.



  • @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();

    QString::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);
    

    QByteArray::data:

    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()



  • @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 index byteArray[byteArray.size()], i.e. 1 beyond the length returned by QByteArray::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 allocate char *str = new char[qbytearray.size()+1]; as @ad1170 did. If you don't do the + 1 then the strcpy() will copy the terminating \0 to 1 byte beyond the allocated area, leading to potential nasties...!


  • Qt Champions 2019

    @JonB You're right. For new/malloc and strcpy the additional \0 has to be considered.



  • @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.


  • Qt Champions 2019

    @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.


  • Lifetime Qt Champion

    Hi @gibbogle,

    Glad to hear that. So please mark this topic as SOLVED too.

    Thanks!


Log in to reply