printf对参数的顺序敏感吗?

时间:2015-12-22 08:19:25

标签: c++ printf zero

我想在 c ++

中使用 printf 打印一个简单的行
    int t0 = time(NULL);
    int outIndx = 99736;
    printf ("time using recurision = %d secs, the result is = %d\n",(time(NULL) - t0), outIndx);

在这种情况下,printf的输出为:

使用recurision的时间= 0秒,结果是= 0

但是当逆转 outIndx (时间(NULL) - t0)的顺序时

printf ("time using recurision = %d secs, the result is = %d\n", outIndx,(time(NULL) - t0));

正确打印printf的输出:

时间使用recurision = 99736秒,结果是= 0

为什么会这样?

4 个答案:

答案 0 :(得分:2)

time会返回time_t,其大小不必与int相同。在这种情况下,%d不是输出的正确格式。

答案 1 :(得分:1)

所以,回答原来的问题。 “printf对参数的顺序是否敏感?”

函数的参数未在标准中定义的顺序,并由编译器使用的调用约定确定。让我们假设您正在使用cdecl调用约定(许多C编译器用于x86体系结构)使用函数中的哪些参数从从右到左进行评估。

让我们举个例子

route.php

这是因为参数是从左到右进行评估的。

但是,在您的示例中,您尝试打印时间类型为“time_t”的ID,如下所示:

int i=5;
    printf("%d%d%d%d%d%d",i++,i--,++i,--i,i);
Output :45545

time_t数据类型是为存储系统时间值而定义的ISO C库中的数据类型。这些值从标准time()库函数返回。此类型是标准头中定义的typedef。 ISO C将time_t定义为算术类型,但未指定任何特定类型,范围,分辨率或编码。同样未指明应用于时间值的算术运算的含义。

它取决于下划线体系结构是否以整数形式实现。就您的示例而言,我认为它没有实现为“unsigned int”atleast(int t0),因此结果是实现定义的

答案 2 :(得分:1)

A C解决方案

通常,显示time_t值的方法是使用struct tmgmtime()将其组件细分为localtime()并显示或转换为strftime()需要使用ctime()difftime()直接从time_t转到显示当地时间的字符串。

如果您想出于某种目的看原始值,C标准指定time_t是实数,这意味着它是整数或浮点数(C 2011(N1570)6.2.5 17)。因此,您应该使用Demo将时间差转换为double:

#include <ctime>
#include <cstdio>

void process()
{
    static unsigned dummy = 0;
    for (size_t i = 0 ; i < 1000000000 ; ++i)
    {
        dummy += (dummy + i) / (dummy * i + 1);
    }
}

int main()
{
    const time_t t0 = time(NULL);
    process(); // let say it can take up to a few hours
    const time_t t_end = time(NULL);

    struct tm breakdown_time = { 0 };
    breakdown_time.tm_sec = difftime(t_end, t0);
    (void) mktime(&breakdown_time);
    printf("duration: %.2d:%.2d:%.2d\n", breakdown_time.tm_hour, breakdown_time.tm_min, breakdown_time.tm_sec);
    // Output: "duration: 00:00:08"
}

std::clock()

C ++解决方案

但是你还没有使用C ++吗? Demo提供了一种计算CPU持续时间的方法(CPU花费的时间,而不是计算在其他线程上花费的时间):

#include <iostream>
#include <iomanip>

void process()
{
    static unsigned dummy = 0;
    for (size_t i = 0 ; i < 1000000000 ; ++i)
    {
        dummy += (dummy + i) / (dummy * i + 1);
    }
}

int main() {
    const std::clock_t t0 = std::clock();
    process(); // business code that take time to run
    const std::clock_t t_end = std::clock();
    const double duration = static_cast<double>(t_end - t0) / CLOCKS_PER_SEC;
    std::cout << "duration: " << std::setprecision(3) << duration << " s" << std::endl;
    // Output: "duration: 8.92 s"
}

std::chrono

A C ++ 14解决方案

我偶然发现了一种优雅,多功能的计算实际持续时间的方法,它在C ++ 14中使用Demo中的所有高级工具:

#include <iostream>
#include <iomanip>
#include <chrono>

void process()
{
    static unsigned dummy = 0;
    for (size_t i = 0 ; i < 100000000 ; ++i)
    {
        dummy += (dummy + i) / (dummy * i + 1);
    }
}

template<typename TimeT = std::chrono::milliseconds>
struct measure
{
    template<typename F, typename ...Args>
    static typename TimeT::rep execution(F&& func, Args&&... args)
    {
        auto start = std::chrono::system_clock::now();
        std::forward<decltype(func)>(func)(std::forward<Args>(args)...);
        auto duration = std::chrono::duration_cast< TimeT> 
                            (std::chrono::system_clock::now() - start);
        return duration.count();
    }
};

int main() {
    std::cout << "duration: " << measure<>::execution(process) << " ms" << std::endl;
    // Output: "duration: 707 ms"
}

{{3}}

答案 3 :(得分:1)

传递给printf(变量参数函数)的所有参数在调用时被推送到堆栈。 printf例程根据第一个参数中提供的%标识符串行弹出参数。取决于堆栈上的参数的机器和编译器顺序(从上到下或从下到上)可能会有所不同。

在您的情况下,当您首先传递(time(NULL) - t0)时,因为它的类型为time_t,并且其大小与printf解释相同,只需看%d。它会产生问题。

现在为什么当你将(time(NULL) - t0}作为第二个参数传递时它起作用:

同样的逻辑,假设你的情况下的timt_t是8个字节,其中int是4个字节。对于每个%d,printf将从参数堆栈中消耗4个字节。因此,当您首先打印outIdx(int)时,printf从对应于outIdx的堆栈中获取正确的4个字节。当printf看到第二个%d时,它将使用4个下一个字节,它是time_t对象的8个字节的一部分。并且取决于time_t的值,系统的字节顺序,print将从堆栈中打印4个字节(8个),假设它为int。

当print提供错误的%标识符时,您最终可能会弄乱其堆栈排列并可能会出现不正确或未定义的行为。