2011-07-27 22 views
1

我想修改我的日誌類接受我的字符串中的變量。例如,如果我想輸出一個地區有7名玩家。修改日誌類接受字符串中的變量 - C++

這是我寫日誌功能:

void Log::writeSuccess(string text,...) 
{ 
    // Write the sucessfull operation to the logfile 
    logfile << "<---> " << text << endl; 
} 

這裏是我的調用代碼:

int playernum = 7; 

errorLog.writeSuccess("There are %i players in the area", playernum); 

它只是最終輸出到文件:有%我的球員在該地區

有什麼辦法解決這個問題?

+2

我很驚訝這不會導致編譯器錯誤,因爲你傳遞了錯誤的參數數量。你的問題的答案可能是boost.log或boost.format,或者如果你有C++ 0x,可能是可變參數模板。 –

+2

你預計發生魔法? –

+0

你是否喜歡printf之類的可變參數函數? – sergio

回答

-7

如果您不能或不會使用升壓:

void Log::writeSuccess(const char* const fmt, ...) { 
    va_list ap; 
    va_start(ap, fmt); 
    char buff[1024]; 
    vsnprintf(buff, sizeof(buff), fmt, ap); 
    logfile << buff; 
} 

注:它假定書面的長度是有限的。

更新:使用gcc可以以類型安全的方式做到這一點,您需要以下聲明。

class Log { 
    void writeSuccess(const char* const fmt, ...) __attribute__ ((format (printf, 2, 3))); 
    //... 
}; 

信息here。注意:這是一個警告,而不是編譯錯誤。如果忽略警告那是你的問題.. :)

+0

謝謝!我很感激。 –

+7

魔法數字讓小狗CRY變得多可怕。千萬不要這樣寫代碼。 – Puppy

+2

紅色警戒,紅色警戒,一個簡單的說明示例中的幻數*嘆息* –

6

我不知道你的程序如何編譯?! 您使用2個參數調用writeSuccess,而聲明它只接受一個參數。

你應該看看boost format

+1

我敢打賭,他還沒有編譯它:) – foxy

+1

對不起,它擺弄它。我在發佈之前恢復了編譯的內容。 –

+0

我看不出爲什麼這仍然會得到提升。它顯然不適用於問題中的代碼了。在投票之前,你們不覺得呢? – sbi

0

stdarg標準庫。它允許您處理可變數量的參數。

+1

這是printf等使用的解決方案,但它是非常類型不安全的。 IMO升壓格式更好 –

+0

@Armen Tsirunyan:我同意。 –

2

使用printf風格的格式字符串的問題是,這些字符串是

  1. 取決於類型提供的參數,並
  2. 依賴於提供參數的訂單

這不僅是容易出錯當你寫的那些行。根據我的經驗,參數的類型和順序很容易在主動維護和擴展的軟件中改變,並且要保持格式化字符串與稍後應用的更改同步更加困難,而最初寫入碼。

需要到手動保存的參數類型同步與格式字符串的問題可以很容易地在C++來解決,已經證明了25年前。Boost.Format甚至可以將格式字符串與類型安全性結合起來。

一種不同的方法,解決這兩個問題,採取的是我看到了一些日誌庫:他們使用指定哪些參數是要在特定的地點在字符串中使用參數的名稱插入語法,他們釋放您不必通過所有參數分別轉換爲字符串去想參數的類型插入之前:

log("i now has the value of @(i), current size is @(x.get_size(y))", 
    LOG_PARAM(i) + LOG_PARAM(x.get_size(y))); 
1

如果你不想使用STDARG.H這沒有按」你看擅長C++ IMO。你可以做這樣的事情。請記住,雖然這是一個小班(爲了更好的日誌記錄你可以添加它),但它不是最有效的方法。

#include <iostream> 
#include <sstream> 


class Log 
{ 
public: 
    Log() : os() 
    { 

    } 

    ~Log() 
    { 
     fprintf(stderr, "%s\n", os.str().c_str()); 
    } 

    template<typename T> 
    std::ostringstream &operator<<(const T &t) 
    { 
     os << "Log file - " << t; 
     return os; 
    } 

private: 
    std::ostringstream os; 
}; 

int main(int argc, char *argv[]) 
{ 
    //usage 
    for (int i = 0; i < 10; ++i) 
     Log() << "Hello world " << i; 

    return 0; 
}