2016-06-10 24 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