簡體   English   中英

std::string::operator=(char): 哪個編譯器是對的? 以及如何測試這種錯誤?

[英]std::string::operator=(char): Which compiler is right? And how to test for this kind of bug?

我在代碼中遇到了這個奇怪的錯誤。 該錯誤本身很常見...由於我打開了一個測試用例,因此我決定對其進行測試...我發現很難測試這種情況。

這是代碼的概述:

#include <string>
#include <cstring>
#include <iostream>

// -------------------------------------------------------------------------
// simulating what is the C driver FYI, it's the alsa sound driver, 
// but that's not much relevant

char* some_text = nullptr;

void init_text()
{
    some_text = strdup("some text");
}

int get_card_name(int, char** x)
{
    *x = some_text;
    return 0;
}

//  end 'driver' code  
// -------------------------------------------------------------------------

int main()
{
    int i = 0;
    char* name;
    std::string s;

     // my original bug...  &"à! happens.
     s = get_card_name(i, &name);

     // Should have read:
     // if (!get_card_name(i, &name))
     //    s = name;

    // simulating EXPECT_FALSE(s.empty());
    std::cout << "s.empty()      : " << s.empty() << '\n';

    // simulating EXPECT_NE(s.length(), 0);
    std::cout << "s.length()     : " << s.length() << '\n';

    // simulating EXPECT_NE(s, "");
    std::cout << "(s == \"\")      : " << (s == "") << '\n';

    // a trace to check contents:
    std::cout << "s              : \"" << s << "\"\n";

    if (!s.empty())
        std::cout << "int(s.front()) : " << (int)s.front() << '\n';

    free(some_text);
    return s.length();
}

它看起來很簡單,但這里是 output 和 gcc 10.2 -Wall,但沒有警告:(:

s.empty()      : 0
s.length()     : 1
(s == "")      : 0
s              : ""
int(s.front()) : 0

使用 clang 11.0.1 -Wall,但沒有警告:(:

s.empty()      : 0
s.length()     : 1
(s == "")      : 0
s              : ""
int(s.front()) : 0

並且使用 msvc 19.28 -Wall,以及超過 100 行警告:(:

s.empty()      : 1
s.length()     : 0
(s == "")      : 1
s              : ""

事實證明,我的這個相當微不足道的錯誤很難測試,至少對於 gcc 和 clang 而言。 想到三個問題...

  • 哪個編譯器是對的?
  • Detecton不是那么明顯。 我們如何防止這種“簡單”的錯誤?
  • gcc 和 clang stl 實現是否應該受到責備? 我應該報告錯誤嗎?

您也可以在這里找到代碼: https://godbolt.org/z/9WhaGzTz8

[編輯] 作為思考的食物......

從上面的代碼中獲取字符串 s ......因為我主要關心的是用於檢測生產代碼中的錯誤的正確單元測試。

gcc 和 clang 報告

 (s == s.c_str()) is false

這確實抓住了這個錯誤,但不平等看起來很奇怪......這是否意味着某些東西在標准方面被打破了?

哪個編譯器是對的?

以下 output 是正確的:

 s.empty(): 0 s.length(): 1 (s == ""): 0 s: "" int(s.front()): 0

s = get_card_name(i, &name); 應該調用basic_string& operator=( CharT ch ); 這將導致字符串包含單個字符 object。 在這種情況下,值為 0,這意味着字符串將包含單個 null 終止符(除了字符串內容之后的 null 終止符)。

我們如何防止這種“簡單”的錯誤?

直接初始化變量,而不是稍后分配。 這通常是最佳實踐,在這種情況下會保護您,因為字符串沒有接受單個 integer 的構造函數。

std::string s = get_card_name(); // ill-formed

還有一些編譯器選項可以警告隱式轉換:

 warning: conversion from 'int' to 'char' may change value [-Wconversion]

這樣的選項通常過於嘈雜而無法無條件啟用,但當您知道存在需要定位的錯誤時,它可能偶爾有用。


也避免不必要的“輸出”參數。 在這種情況下:

char* get_card_name()
{
    return some_text;
}

std::string s = get_card_name(); // works as expected

當然,這更多的是關於如何編寫API,而不是關於如何處理難以使用的API。 有了這些,你需要仔細的勤奮。

實現一個更易於使用的包裝器 API 是一個好主意,這樣就不需要直接使用 C 風格的 API。


gcc 和 clang stl 實現是否應該受到責備? 我應該報告錯誤嗎?

不,它們工作正常。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM