2016-06-10 79 views
3

我正在修復我繼承的遺留項目中的編譯器警告。新編譯器是gcc版本4.8.5 20150623(Red Hat 4.8.5-4)(GCC)。C++ printf字段寬度說明符'。*'預計int不是size_t

他們是許多像以下代碼:

#include <cstdio> 
#include <cstring> 

struct foobar 
{ 
    char field1[10]; 
    char field2[5]; 
}; 

int main() 
{ 
    struct foobar foo; 
    memset(&foo, ' ', sizeof(foo)); 
    strncpy(foo.field1, "1234567890", sizeof(foo.field1)); 

    // Produces warning 
    printf("[%.*s]", sizeof(foo.field1), foo.field1); 

    return 0; 
} 

這會產生一個警告信息:「*」

1_test.c: In function ‘int main()’: 
1_test.c:16:49: warning: field precision specifier ‘.*’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=] 
    printf("[%.*s]", sizeof(foo.field1), foo.field1); 

這似乎是我錯了。應該想到的size_t,但顯然它不...

是否有無論如何解決這個問題,除了必須做以下事情之外:

// Fixes 
    printf("[%.10s]", foo.field1); 

    // Fixes 
    printf("[%.*s]", static_cast<int>(sizeof(foo.field1)), foo.field1); 
+0

我剛纔說「使用static_cast'」但你是對的,這是一個醜陋的解決方案。 –

+0

的printf不是C++ – Slava

+1

@Slava它不是C++,但它是它 – KABoissonneault

回答

0

你總是有unfun但有時最好的解決方案在宏

#define INT_SIZEOF(x) static_cast<int>(sizeof((x))) 

printf("[%.*s]", INT_SIZEOF(foo.field1), foo.field1); 

來包裝。如果你的代碼是宏過敏,可以爲static_cast做一個簡單的語法包裝,這樣

int AsInt(size_t n) { return static_cast<int>(n) } 
printf("[%.*s]", AsInt(sizeof(foo.field1)), foo.field1); 

正如評論中所述,該解決方案只能取一個大小值,因此需要單獨的sizeof運算符。另外,如果sizeof沒有返回一個符合整數的值(儘管不太可能),那麼在編譯時錯誤檢查中你將失去任何機會。

注意,在這兩種情況下,你的代碼仍然是醜陋,但至少有一個是短,並通知醜陋的東西是怎麼回事讀者。

最後,另一個可能的體面的選擇。

// constexpr is optional, you simply won't be able to use it in as many places if you don't use it 
template<typename T> constexpr int intSizeof(T = T{} /*replace with() if necessary*/) 
{ 
    return static_cast<int>(sizeof(T)); 
} 

printf("[%.*s]", intSizeof<decltype(foo.field1)>(), foo.field1); 

這個解決方案絕對是更加C++和更現代,在沒有真正的成本

+0

這將如何成爲「最佳解決方案」?宏在這裏做什麼,一個函數不能? –

+0

@CodyGray在編譯時進行評估。另外,宏可以同時使用這兩種類型和表達式,而函數或類型轉換隻能使用它們中的任何一種。 (是的,函數和typetraits也可以在特定條件下評估編譯時間) – KABoissonneault

+0

如果您使用的編譯器不能內聯包含靜態轉換和sizeof運算符的函數,那麼您應該基本放棄。你沒有使用宏在這裏傳遞一個類型,你使用它來傳遞一個值,所以我不明白這是如何適用的......? –

2

正確的解決辦法是:

std::cout << std::string(foo.field1, sizeof(foo.field1)); 

這會產生你的願望輸出和沒有任何警告。但更好的解決方案當然是使用std::stringstruct foobar