0 == 1 == 2 ???



  • Okay, this has to be the most ridiculously frustrating bug I have seen to date using Qt.

    All I am trying to do is set up a GUI with 3 buttons, each with its own enum. If the enum is equal to Reboot (2), then the system is supposed to reboot. If the enum is 0 or 1, the process is supposed to call a different command.

    Initially when I was typing "transitionTo.goToNext(transitionTo.EnumValue)", it was interpeting the int as a unicode character, which I didn't know how to deal with and didn't want to spend the time learning.

    Now, I am just sending single character strings. In transition_functions.cpp, num.toInt() always prints the correct enum integer value, but whether it is 0, 1, or 2, num.compare("2") == 0 always returns true, because the reboot command executes for every button pressed!!! Extremely frustrated with this trivial code. Please help and/or shed some light on this tomfoolery.

    I should also mention that the second script command is a placeholder at this point.

    main.cpp:

    #include "transition_functions.cpp"
    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQmlContext>
    #include <QChar>
    
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
        QQmlApplicationEngine engine;
        transition_functions *context_property = new transition_functions();
        context_property->passPid(app.applicationPid());
        qDebug() << transition_functions::App_ScreenTest << "," << transition_functions::App_UiTest << "," << transition_functions::Reboot;
        QQmlContext *context = engine.rootContext();
        context->setContextProperty("transitionTo",context_property);
    
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
        if (engine.rootObjects().isEmpty())
            return -1;
    
        return app.exec();
    }
    

    transition_functions.h:

    #include <QObject>
    #include <QProcess>
    #include <QString>
    #include <QStringList>
    #include <QDebug>
    
    class transition_functions: public QObject
    {
        Q_OBJECT
        Q_ENUMS(Next)
    
    public:
    
        enum Next { App_UiTest, App_ScreenTest, Reboot};
    
        transition_functions(QObject *parent = nullptr): QObject(parent) { }
    
        Q_INVOKABLE void goToNext(QString num);
        void passPid(int val) { _appPid = val; }
        virtual ~transition_functions() { }
    
        int _appPid;
    
    };
    

    transition_functions.cpp:

    #include "transition_functions.h"
    
    
    void transition_functions::goToNext(QString num) {
    
            QProcess *proc = new QProcess();
            qDebug() << "button pressed: " << num.toInt();
            if (num.compare("2") == 0) {
    
                if (num.toInt() != 2) { qDebug() << "this is fucked."; }
                proc->start("/bin/bash",QStringList() << "-c" << "echo 'reboot' > /dev/ttyS0");
            } else {
    
            QString command = "echo '. scriptpathname.sh " + QString(QString::fromStdString(std::to_string(_appPid))) + " " +
            num + "' > /dev/ttyS0";
            //passes the pid and the chosen app based on the button press.
    
            proc->start("/bin/bash", QStringList() << "-c" << command);
            }
    }
    

    main.qml:

    Window {
        visible: true
        width: 800
        height: 480
        title: qsTr("thing")
    
        MainForm {
            anchors.fill: parent
            testButton.onClicked: transitionTo.goToNext("0") //App_UiTest
            screenButton.onClicked: transitionTo.goToNext("1") //App_ScreenTest
            powerButton.onClicked: transitionTo.goToNext("2") //Reboot
        }
    }
    
    

  • Lifetime Qt Champion

    Hi,

    A quick test shows that:

    qDebug() << QString("0").compare("2")
                      << QString("1").compare("2")
                      << QString("2").compare("2");
    

    returns -2, -1, 0 respectively.

    By the way, why not compare the int value since you convert it anyway ?



  • @SGaist

    I did at one point compare int values, but now I am trying strings.

    Your quick test confirms my frustration; why would the if statement

    if (num.compare("2") == 0)
    

    be true for num equal to "0", "1", & "2" ? It should be false for 2 of the cases, but it's true for all 3.


  • Lifetime Qt Champion

    What do you get printed on your application output ?


  • Qt Champions 2017

    Hi
    What Qt version are you using ?
    Cant reproduce either

    QString num = "2";
      if (num.compare("0") == 0 ) { qDebug() << "TRUE 0"; }
      if (num.compare("1") == 0 ) { qDebug() << "TRUE 1"; }
      if (num.compare("2") == 0 ) { qDebug() << "TRUE 2"; }
    

    says
    TRUE 2



  • @devDawg said in 0 == 1 == 2 ???:

        qDebug() << "button pressed: " << num.toInt();
        if (num.compare("2") == 0) {
    
            if (num.toInt() != 2) { qDebug() << "this is f***ed."; }
    

    I don't really believe this code can be followed to printing the rude message if num != "2" (unless something is seriously wrong with your Qt).

    But why not use the optional parameter for http://doc.qt.io/qt-5/qstring.html#toInt

    Returns 0 if the conversion fails.
    If a conversion error occurs, *ok is set to false; otherwise *ok is set to true.

    bool ok;
    int result = num.toInt(&ok);
    

    What is the value of ok? Because if by any chance it's false, somehow, the toInt() would return 0, which would result in it following your "unexpected" num.toInt() != 2 route....



  • @mrjj 5.9.3, unfortunately. The device that I am building the app for is configured for an older version of Qt. As for your test, I got the same result.

    @JonB I never gave the optional parameter a thought, that's a very good point. I apologize for the rude message, I have just been really frustrated by this.

    transition_functions.cpp:

    void transition_functions::goToNext(QString num) {
    
            QProcess *proc = new QProcess();
            bool ok;
            qDebug() << "button pressed: " << num.toInt(&ok);
            qDebug() << "conversion was " << ok;
            if (num.compare("2") == 0) {
    
                qDebug() << "reboot triggered" ;
                proc->start("/bin/bash",QStringList() << "-c" << "echo 'reboot' > /dev/ttyS0");
    
            } else {
    
            QString command = "echo '. scriptpathname.sh " + QString(QString::fromStdString(std::to_string(_appPid))) + " " + num + "' > /dev/ttyS0";
            //passes the pid and the chosen app based on the button press.
    
            proc->start("/bin/bash", QStringList() << "-c" << command);
            }
    }
    

    Upon testing each button press this morning, these are the results:

    pressing the App_UiTest button (0),

    button pressed: 0
    ok == true
    

    pressing this button triggered a reboot, without printing the "reboot triggered" message within the if statement.

    pressing the App_ScreenTest button (1),

    button pressed: 1
    ok == true
    

    pressing this button also triggered a reboot, & again did not print the "reboot triggered" message within the if statement.

    pressing the Reboot button (2),

    button pressed: 2
    ok == true
    reboot triggered
    

    everything here is the same as the other 2 buttons, except we actually see the "reboot triggered" message get printed.

    I am not sure what to make of these results. It is almost as if in the first 2 cases, the reboot function is being triggered without even entering the if statement.

    So I modified the test slightly by commenting out all the code in the else statement, leaving only a print statement "no reboot." Now when I pressed the buttons, they behave as expected. This only happened when I commented out the
    proc->start() command in the else statement. Interesting to say the least.

    Any thoughts?



  • @devDawg
    So if I understand correctly, I see the following behaviour:

    • The num.toInt(&ok) always succeeds, and always returns the correct number.

    • The num.compare("2") always correctly matches "2" and only "2". The correct path of its if ... else is always followed.

    • The above two statements are as to be expected. Whatever your problem is, it is not to do with number parsing. Any time you think it is again, isolate only the parsing code (not your actions) and verify that parsing is not at issue. It can't be. This is the answer to your question as originally posted.

    • When it follows the if it always correctly correctly prints the reboot message and reboots.

    • But when it follows the else path, it does not print a reboot message (correct) but it still reboots. Though if you replace the else's proc-start() with a "no reboot" statement you get that message but no reboot.

    The only conclusion is that the else''s proc->start() is itself causing a reboot, whether you like it or not!

    Now, I don't know what might be in your scriptpathname.sh, maybe that causes a reboot (umm, what does it do? you haven't left a reboot in there, have you????) ... Or, writing anything to /dev/ttyS0 causes a reboot. Or, ....

    I can't do your debugging for you. I am confident that the number parsing is not at issue (code is following correct path), and I am confident that when the else path is followed whatever it does it does not "magically" execute the proc->start() from the if route.

    There is much more playing you can do to satisfy yourself about what must, or must not, be going on. For example, your two proc->start()s could both echo stuff into some files instead of to /dev/ttyS0 so that you can see what's going on.



  • @JonB scriptpathname.sh, as I stated earlier, is not a valid script, it is simply a placeholder.

    Thanks for the help!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.