uint_fast16_t的sprintf格式?

时间:2014-06-20 13:55:21

标签: c++ printf

我遇到了uint_fast16_t格式问题

    uint_fast16_t runningOrderNo;

    std::string ATNativeConnector::_GetNextClOrdId()
{

    time_t t = time(NULL);
    struct tm* tim = localtime(&t);

    std::stringstream sstr;
    char temp[10];
    sprintf(temp, "%02d%02d%02d%03u", tim->tm_hour, tim->tm_min, tim->tm_sec, ++runningOrderNo);
    sstr << temp; //<< std::setfill('0') << std::setw(2) << tim->tm_hour << tim->tm_min <<  tim->tm_sec << ++runningOrderNo;
    runningOrderNo %= 999;

    //LOG4CXX_DEBUG(logger,"Generated " << sstr.str() << " second:" << tim->tm_sec << " order id");
    return sstr.str();
}

我收到这样的警告。

ATNativeConnector.cpp:6156:95:警告:格式'%u'需要'unsigned int'类型的参数,但参数6的类型为'uint_fast16_t {aka long unsigned int}'[ - Wformat =]

我在this页面尝试了不同的格式,如果有人会帮助我,我们会感激不尽。

3 个答案:

答案 0 :(得分:10)

正确的方法是使用您链接的页面中的PRIuFAST16宏:

sprintf(temp, "%02d%02d%02d%03" PRIuFAST16, ..., ++runningOrderNo);

宏扩展为一个字符串,然后由预处理器与相邻的字符串文字连接。这样,略看怪的"%02d%02d%02d%03" PRIuFAST16最终会成为包含正确格式说明符的一个字符串文字。

答案 1 :(得分:2)

使用PRIuFAST16宏,sth's answer建议,是最正确的解决方案。

另一种选择(我发现它更具可读性)是将参数转换为已知类型。例如:

uintfast_16_t n = 42;
printf("%lu\n", (unsigned long)n);

你必须小心选择一个足够宽的类型来保存被转换的值;从理论上讲,uintfast_16_t可能比unsigned long更宽,但不太可能。 (在这种情况下,unsigned int几乎肯定是足够好的。)

如果你是偏执狂,请使用uintmax_t

printf("%ju\n", (uintmax_t)n);

这种方法的优点是您和代码的任何读者都不必记住(或查找)相当简洁的宏名称。

缺点是选择不够宽的类型以及在打印操作数之前将操作数转换为更宽类型的(非常小的)效率低的风险。

当然使用std::stringstream而不是sprintf可以完全避免这个问题。

答案 2 :(得分:0)

正如其他人正确指出的那样,您必须将PRIuFAST16宏与printf一起使用。但是,由于您询问的是C ++(基于标记),因此建议您完全避免使用printf,并使用类型安全的替代方法,例如the {fmt} library

#include <fmt/core.h>

auto s = fmt::format("{:02}{:02}{:02}{:03}",
                     tim->tm_hour, tim->tm_min, tim->tm_sec, ++runningOrderNo);

请注意,您可以省略所有类型说明符(duPRIuFAST16),因为fmt::format基于可变参数模板并保留类型信息。

为基于C ++ 20的标准化,提出了基于该库的格式化工具:P0645

此外,您可以对字符串的日期部分使用类似strftime的格式,以进一步提高可读性:

#include <fmt/time.h>

auto s = fmt::format("{:%H%M%S}{:03}", *tim, ++runningOrderNo);

免责声明:我是{fmt}的作者。