C ++ printf字段宽度说明符'。*'期望int不是size_t

时间:2016-06-10 16:31:40

标签: c++ printf

我正在修复我继承的遗留项目中的编译器警告。新编译器是gcc版本4.8.5 20150623(Red Hat 4.8.5-4)(GCC)。

他们有很多代码如下:

#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);

这对我来说似乎是错误的。&#39;。&#39;应该期待一个size_t,但显然它没有......

除了必须执行以下操作之外,还有全局解决此问题的方法:

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

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

2 个答案:

答案 0 :(得分:2)

正确的解决方案是:

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

这将输出您想要的内容而不会产生任何警告。但更好的解决方案当然是在std::string

中使用struct foobar

答案 1 :(得分:0)

你总是拥有一个未经展开但有时候最好的解决方案来包装宏

#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 ++和更现代的,没有实际成本