无符号字符 * 产生奇怪的字符,使其始终无法比较

Unsigned char * produce weird characters which make it always failed to compared

提问人:Kevinkun 提问时间:8/29/2021 更新时间:8/30/2021 访问量:417

问:

我总是有这个问题,尤其是当它是从某个函数返回的类型时。我的问题是,我有一个数据库,我想从表中选择其中一列。然后用 获取值。unsigned char*sqlite3_column_text()

这是代码:

void check_username(std::string username)
{
    sqlite3_stmt* stmt;
    std::string query = "SELECT username FROM bank_account WHERE username = '"+ username +"';";
   
    int rc = sqlite3_prepare_v2(DB, query.c_str(), -1, &stmt, NULL);
    if (rc != SQLITE_OK) 
    {
        std::cerr << "Error: " << sqlite3_errmsg(DB) << std::endl;
        return -1;
    }
    
    // Move to result of query's row
    rc = sqlite3_step(stmt);

    // Get the column value
    const unsigned char* result = sqlite3_column_text(stmt, 0);
    // Convert std::string username to unsigned char* for comparison with text in result
    const unsigned char* new_username = reinterpret_cast<const unsigned char*>(username.c_str());


    sqlite3_finalize(stmt);
    
    
    // THIS WILL FAILED TO COMPARE //
    if (new_username == result)
        std::cout << "It's match! << std::endl;
    else
        std::cout << "It's not match! << std::endl;
}

它说返回,所以这就是为什么我将其存储在相同类型的变量中:sqlite3_column_text()unsigned char*

const unsigned char* result = sqlite3_column_text(stmt, 0);

然后正如你所看到的,我的函数作为参数。因此,为了将其与数据库的结果进行比较,我将其转换为无符号字符:std::string

const unsigned char* new_username = reinterpret_cast<const unsigned char*>(username.c_str());

问题来了:在代码的末尾,它总是无法比较,即使名称匹配,它也总是会变成假。然后我尝试调试,这是输出:std::cout << result << std::endl;std::cout << new_username << std::endl;

�S�U
Harrypotter

所以从中产生的那个奇怪的字符。所以,我认为这就是为什么当我试图比较时它总是不匹配的原因。sqlite3_column_text()

所以我的问题是,这是怎么发生的?有什么解决方案可以让我进行比较?

C++ SQLite 无符号

评论

0赞 Pepijn Kramer 8/29/2021
您正在比较指针。尝试反其道而行之,从结果创建一个 std::string,然后比较 std::string 变量。
0赞 Kevinkun 8/29/2021
@PepijnKramer我不认为这没有问题。只要它们都包含字符串。我试过了。

答:

0赞 Pepijn Kramer 8/29/2021 #1

喜欢这个:

void check_username(const std::string& username) // added const&
{
....
    // Get the column value, create string from char*
    std::string new_username{ static_cast<const char*>(sqlite3_column_text(stmt, 0)) }; // <========

    sqlite3_finalize(stmt);
    
    // now compare the std::string variables instead of pointers
    if (new_username == username)
        std::cout << "It's match! << std::endl;
    else
        std::cout << "It's not match! << std::endl;
}

评论

0赞 Kevinkun 8/29/2021
它失败了。它不能像那样存储。sqlite3_column_text()std::string
0赞 Kevinkun 8/29/2021
错误说:no instance of constructor "std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string [with _CharT=char, _Traits=std::char_traits<char>, _Alloc=std::allocator<char>]" matches the argument list -- argument types are: (const unsigned char *)
0赞 Pepijn Kramer 8/29/2021
而且我无法编译所有sql的东西。哦,sql 方法返回一个 const unsigned char* 我没有注意到,std::string 需要一个 const 签名的 char*。嗯,尝试 std::string new_username{ static_cast<const char*>(sqlite3_column_text(stmt, 0)) };(通常我们要求一个可编译的代码示例,但我可以看到循环中的sql lite很难)
0赞 Ruks 8/29/2021 #2

在这一行中:

if (new_username == result)

您不能像这样比较两个单独的指针。指针本质上只是 内存地址,并考虑到并引用内存中的不同位置,上述条件将永远无法满足。resultnew_username

如果要比较内容,有三个选项:

  1. 使用 std::equal():

    #include <cstring>
    #include <algorithm>
    
    // Do prefer using `const std::string&` over just `std::string` in the parameter to avoid temporary copies
    void check_username(std::string const& username) {
        // ...
    
        const unsigned char* result = sqlite3_column_text(stmt, 0);
    
        // ...
    
        if (std::equal(username.begin(), username.end(),
                       result, result + std::strlen(reinterpret_cast<const char*>(result))))
            std::cout << "It's match!" << std::endl;
        else
            std::cout << "It's not match!" << std::endl;
    }
    
  2. 对字符串使用 operator==() 比较运算符:

    #include <cstring>
    
    // ...
    
    void check_username(std::string const& username) {
        // ...
    
        const unsigned char* result = sqlite3_column_text(stmt, 0);
    
        // ...
    
        if (username == std::string(result, result + std::strlen(reinterpret_cast<const char*>(result))))
            std::cout << "It's match!" << std::endl;
        else
            std::cout << "It's not match!" << std::endl;
    }
    
  3. 使用 std::strcmp():

    #include <cstring>
    
    // ...
    
    void check_username(std::string const& username) {
        // ...
    
        const unsigned char* result = sqlite3_column_text(stmt, 0);
    
        // ...
    
        if (std::strcmp(&username[0], reinterpret_cast<const char*>(result)) == 0)
            std::cout << "It's match!" << std::endl;
        else
            std::cout << "It's not match!" << std::endl;
    }
    

评论

0赞 Kevinkun 8/30/2021
它失败了。所有这一切。就像我说的,它总是打印“它不匹配!即使我知道它的名字相同。
0赞 Ruks 8/30/2021
@Kevinkun 您是否尝试过检查和使用调试器的值,或者查看它们是否匹配?usernameresultstd::cout
0赞 Kevinkun 8/30/2021
是的,这是匹配的。
0赞 Kevinkun 8/30/2021
我刚刚发现了问题!它开着。在我进行比较之前,它会更改执行时的值。所以,这就是为什么它总是不匹配。sqlite3_finalize(stmt)result
0赞 Kevinkun 8/30/2021
感谢您的解决方案。我正在使用第三个。