简体   繁体   中英

I have piece of code that gets duration from a FILETIME struct. What does it mean?

I have this function

void prtduration(const FILETIME *ft_start, const FILETIME *ft_end) 
{
    double duration = (ft_end->dwHighDateTime - ft_start->dwHighDateTime) *
        (7 * 60 + 9 + 496e-3)
        + (ft_end->dwLowDateTime - ft_start->dwLowDateTime) / 1e7;
    printf("duration %.1f seconds\n", duration);
    system("pause");
}

Could anybody explain the working of the following part of the code?

(ft_end->dwHighDateTime - ft_start->dwHighDateTime) *
            (7 * 60 + 9 + 496e-3)
            + (ft_end->dwLowDateTime - ft_start->dwLowDateTime) / 1e7;

Wow! What an obfuscated piece of code. Let us try to simplify it:

   // Calculate the delta
   FILETIME delta;
   delta.dwHighDateTime = ft_end->dwHighDateTime - ft_start->dwHighDateTime;
   delta.dwLowDateTime = ft_end->dwLowDateTime - ft_start->dwLowDateTime;

   // Convert 100ns units to double seconds.
   double secs = delta.dwHighDateTime * 429.496 + delta.dwLowDateTime/1E7

In actual fact I think this is wrong. It should be:

  double secs = delta.dwHighDateTime * 429.4967296 + delta.dwLowDateTime/1E7

Or even more clearly:

  double secs = (delta.dwHighDateTime * 4294967296. + delta.dwLowDateTime)/10E6

What is happening is that the high time is being multiplied by 2**32 (which converts to 100ns units then divided by 100ns to give seconds.

Note that this is still wrong because the calculation of delta is wrong (in the same way as the original). If the subtraction of the low part underflows, it fails to borrow from the high part. See Microsoft's documentation:

It is not recommended that you add and subtract values from the FILETIME structure to obtain relative times. Instead, you should copy the low- and high-order parts of the file time to a ULARGE_INTEGER structure, perform 64-bit arithmetic on the QuadPart member, and copy the LowPart and HighPart members into the FILETIME structure.

Or actually, in this case, just convert the QuadPart to double and divide. So we end up with:

    ULARGE_INTEGER start,end;
    start.LowPart  = ft_start->dwLowDateTime;
    start.HighPart = ft_start->dwHighDateTime;
    end.LowPart = ft_end->dwLowDateTime;
    end.HighPart = ft_end->dwHighDateTime;

    double duration = (end.QuadPart - start.QuadPart)/1E7;

Aside: I bet the reason that the failure to borrow has never been spotted is that the code has never been asked to print a duration of greater than 7 minutes 9 seconds (or if it has, nobody has looked carefully at the result).

7 is very approximately frequency when FileTime variable changes its value. Namely, every 7 (+-3 or even more) minutes it increases on 1. Than we multiply it on 60 for getting value in seconds.

9 + 496e-3 - is time is seconds that deals somehow with compilation (from the start of the withdrawal to output in the console) that we are losing.

Really, it is very bad code and we shouldn't write like this.

However it have forced me to learn better about FileTime work.

Thanks everyone for answers, I very appreciate it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM