【问题标题】:Convert a QString to a const char*将 QString 转换为 const char*
【发布时间】:2020-11-13 17:41:03
【问题描述】:

为了创建自定义异常类,我需要将QString 转换为const char*。以下是上述类的主要代码:

// File "Exception.cpp"

const auto MESSAGE_PREFIX = QStringLiteral("Exception ");

Exception::Exception(const char* file, int line, const QString& cause)
    : m_Message{MESSAGE_PREFIX + file + ':' + QString::number(line) + ": " + cause}
{
}

const char* Exception::what() const noexcept
{
    // QString -> const char*
    const auto ba = m_Message.toLocal8Bit();
    return ba.constData();
}

因此,转换发生在被覆盖的方法Exception::what 中,并且返回的 C 字符串指示引发异常的文件等。

另外,我定义了一个宏THROW_EXCEPTION_IF(),它有助于抛出异常:

// File "exception_macros.h"

#include "Exception.h"

#ifdef Q_OS_WINDOWS
#define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
#else
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
#endif

#define THROW_EXCEPTION_IF(condition, cause)
    if (condition) {
        auto str = QString{};
        QTextStream stream{&str};
        stream << cause;
        throw Exception{__FILENAME__, __LINE__, str};
    }

最后,我用下面的代码测试了上面的宏:

void TestException::testMacro()
{
    try {
        THROW_EXCEPTION_IF(true, "Test")
        QVERIFY(false);
   }
   catch (const std::exception& e) {
       QVERIFY(true);
       QCOMPARE(QString{e.what()}, QStringLiteral("Exception TestException.cpp:36: Test"));
   }
}

问题是:当我在 Linux(Qt 5.7.1、GCC 6.3)上运行此测试时,它会失败并显示以下消息:

失败!:TestException::testMacro() 比较的值不一样
实际(QString{e.what()}):“异常 TestExn\u0000\u0000T\u0000e\u0000s\u0000t\u0000E\u0000x\u0000n\u0000\u0000\u0000” 预期 (QStringLiteral("Exception TestException.cpp:36: Test")): "Exception TestException.cpp:36: Test"

在 Windows (Qt 5.15) 上使用 MSVC 2019 也是同样的问题,但它适用于 MinGW 8.1。此外,在Linux上,当我将m_Message.toLocal8bit()替换为m_Message.toLatin1()时,测试成功通过。我认为 Unicode 字符有问题,但我不明白我的代码哪里有问题。非常感谢您的帮助。

【问题讨论】:

  • 为什么不直接去my_qstring.toStdString().c_str();
  • @Aziuth 如果他这样做,指针将不再有效,只要他得到它。
  • @Erwan 请提供一些代码和您要转换的字符串。如果您要转换为 Local8Bit,则不同平台之间可能会有所不同。

标签: c++ visual-studio qt qt5


【解决方案1】:

为什么它不起作用

我同意 Pablo Yaggi 的观点,即您正试图访问被破坏的数据,请参阅 QByteArray::constData

只要字节数组未被重新分配,[const char *] 指针就保持有效 或销毁。

解决方案

您应该将QByteArray(由toLocal8Bit 返回)存储在您的异常类中(而不是QString)。请注意,您可能希望返回 UTF-8 编码的字符串(请参阅toUtf8)以支持所有(特殊)字符。如果遇到不支持的字符,toLocal8BittoLatin1 的行为是未定义的:

如果此字符串包含任何无法在 语言环境,返回的字节数组是未定义的。这些字符可能是 被另一个人压制或取代。 [source]

【讨论】:

    【解决方案2】:

    您的问题是您返回的指针无效:

    const auto ba = m_Message.toLocal8Bit(); // here you create a bytearray
    return ba.constData();//here you take the pointer to the data of the bytearray
                          //then you destroy the array, hence the pointer.
                          //then you return an invalid pointer
    

    您在不同的平台上有不同的行为,因为当指针不再可用时,这是不保证的。这取决于平台、编译器、编译标志等。

    【讨论】:

      猜你喜欢
      • 2014-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多