Clock_t प्रिंट करने के लिए printf का उपयोग करने का सही तरीका क्या है?




io (4)

मैं वर्तमान में unsigned long long लिए एक स्पष्ट कलाकार का उपयोग कर रहा हूं और इसे प्रिंट करने के लिए %llu का उपयोग कर रहा हूं, लेकिन चूंकि size_t में %z विनिर्देशक है, तो clock_t पास क्यों नहीं है?

इसके लिए एक मैक्रो भी नहीं है। शायद मैं मान सकता हूं कि एक x64 सिस्टम (ओएस और सीपीयू) size_t लंबाई में 8 बाइट है (और इस मामले में, उन्होंने %z प्रदान किया है), लेकिन clock_t बारे में क्या?


ऐसा कोई सही तरीका नहीं लगता है। समस्या की जड़ यह है कि clock_t या तो पूर्णांक या फ़्लोटिंग बिंदु हो सकता है।

clock_t एक फ़्लोटिंग पॉइंट प्रकार हो सकता है

जैसा कि बैस्टियन लियोनार्ड ने पॉज़िक्स के लिए उल्लेख किया है (उसे ऊपर उठाएं ), सी 99 एन 1256 ड्राफ्ट 7.23.1 / 3 यह भी कहता है कि:

[clock_t] अंकगणितीय प्रकार समय का प्रतिनिधित्व करने में सक्षम है

और 6.2.5 / 18:

पूर्णांक और फ़्लोटिंग प्रकार सामूहिक रूप से अंकगणितीय प्रकार कहा जाता है।

और मानक अंकगणितीय प्रकार को या तो पूर्णांक या फ़्लोटिंग बिंदु प्रकार के रूप में परिभाषित करता है।

यदि आप CLOCKS_PER_SEC द्वारा विभाजित करेंगे, तो लंबे समय तक उपयोग करें

clock() का वापसी मूल्य कार्यान्वयन परिभाषित किया गया है, और इसके मानक अर्थ प्राप्त करने का एकमात्र तरीका है CLOCKS_PER_SEC द्वारा सेकंड की संख्या को खोजने के लिए विभाजित करना:

clock_t t0 = clock();
/* Work. */
clock_t t1 = clock();
printf("%Lf", (long double)(t1 - t0));

यह दो अच्छे कारणों से पर्याप्त है, हालांकि सही नहीं है:

  • फ्लोटिंग पॉइंट प्रकारों के लिए intmax_t लिए कोई एनालॉग नहीं लगता है: intmax_t और उसके printf विनिर्देशक का सबसे बड़ा सटीक फ़्लोटिंग पॉइंट डेटा प्रकार कैसे प्राप्त करें? तो यदि कल एक बड़ा फ़्लोटिंग पॉइंट प्रकार आता है, तो इसका उपयोग किया जा सकता है और आपके कार्यान्वयन को तोड़ दिया जा सकता है।

  • अगर clock_t एक पूर्णांक है, तो फ्लोट करने के लिए कास्ट अच्छी तरह से निकटतम फ्लोट का उपयोग करने के लिए परिभाषित किया गया है। आप परिशुद्धता खो सकते हैं, लेकिन यह पूर्ण मूल्य की तुलना में अधिक मायने रखता नहीं है, और केवल बड़ी मात्रा में होता है, उदाहरण के लिए x86 में long int 64-बिट महत्वपूर्ण के साथ 80-बिट फ्लोट है, जो लाखों वर्षों में है सेकंड।

ऊपर उल्टा नींबू पानी जाओ जो कुछ समान कहा।

यदि आपको लगता है कि यह एक पूर्णांक है, तो% ju और uintmax_t का उपयोग करें

हालांकि unsigned long long वर्तमान में सबसे बड़ा मानक पूर्णांक प्रकार संभव है:

  • भविष्य में एक बड़ा व्यक्ति बाहर आ सकता है
  • मानक पहले से ही स्पष्ट रूप से बड़े कार्यान्वयन परिभाषित प्रकारों (kudos से @FUZxxl) की अनुमति देता है और clock_t उनमें से एक हो सकता है

इसलिए सबसे बड़ा हस्ताक्षर किए गए पूर्णांक प्रकार को टाइपकास्ट करना सबसे अच्छा है:

#include <stdint.h>

printf("%ju", (uintmax_t)(clock_t)1);

uintmax_t मशीन पर सबसे बड़ा संभव पूर्णांक आकार का आकार होने की गारंटी है।

uintmax_t और इसके printf विनिर्देश %ju को c99 और gcc में पेश किया गया था उदाहरण के लिए उन्हें लागू करता है।

बोनस के रूप में, यह एक बार और सभी प्रश्नों के लिए हल करता है कि कैसे विश्वसनीय रूप से printf पूर्णांक प्रकार (जो दुर्भाग्यवश clock_t लिए आवश्यक नहीं है)।

यदि यह डबल था तो क्या गलत हो सकता है:

  • अगर पूर्णांक, अपरिभाषित व्यवहार में फिट होने के लिए बहुत बड़ा है
  • 1 से बहुत छोटा, 0 तक गोल हो जाएगा और आप कुछ भी नहीं देखेंगे

चूंकि उन परिणामों को फ्लोट रूपांतरण के पूर्णांक की तुलना में अधिक कठोर है, फ्लोट का उपयोग करना एक बेहतर विचार है।

Glibc 2.21 पर यह एक पूर्णांक है

मैनुअल का कहना है कि double का उपयोग करना एक बेहतर विचार है:

जीएनयू / लिनक्स और जीएनयू / हर्ड सिस्टम पर, घड़ी_टी लंबी int के बराबर है और CLOCKS_PER_SEC एक पूर्णांक मान है। लेकिन अन्य प्रणालियों में, clock_t और मैक्रो CLOCKS_PER_SEC दोनों या तो पूर्णांक या फ़्लोटिंग-पॉइंट प्रकार हो सकते हैं। ऊपर दिए गए उदाहरण में, CPU समय मानों को दोगुनी करने के लिए, यह सुनिश्चित करता है कि अंकगणित और प्रिंटिंग जैसे ऑपरेशन ठीक से और लगातार काम करते हैं चाहे अंतर्निहित प्रतिनिधित्व क्या हो।

Glibc 2.21 में:

  • clock_t long int :

  • लिनक्स में clock() sys_clock_gettime साथ लागू की sys_clock_gettime :

    man clock_gettime , हमें बताता है कि यह एक struct timespec man clock_gettime देता है जिसमें जीसीसी में long int फ़ील्ड होते हैं।

    तो अंतर्निहित कार्यान्वयन वास्तव में पूर्णांक देता है।

यह भी देखें


सी मानक को विभिन्न प्रकार के आर्किटेक्चर को समायोजित करना होता है, जिससे आंतरिक घड़ी का प्रकार अंकगणित होता है, इस तथ्य से अलग और गारंटी मिलती है।

ज्यादातर मामलों में, आप समय अंतराल में रुचि रखते हैं, इसलिए मैं घड़ी की टिक में मिलीसेकंड में अंतर बदल दूंगा। एक unsigned long लगभग 32 दिनों के अंतराल के लगभग 50 दिनों के अंतराल का प्रतिनिधित्व करने के लिए काफी बड़ा है, इसलिए यह ज्यादातर मामलों के लिए काफी बड़ा होना चाहिए:

clock_t start;
clock_t end;
unsigned long millis = (end - start) * 1000 / CLOCKS_PER_SEC;

gettimeofday फ़ंक्शन का उपयोग करके एक तरीका है। कोई भी इस फ़ंक्शन का उपयोग करके अंतर पा सकता है:

unsigned long  diff(struct timeval second, struct timeval first)
{
    struct timeval  lapsed;
    struct timezone tzp;
    unsigned long t;

    if (first.tv_usec > second.tv_usec) {
        second.tv_usec += 1000000;
        second.tv_sec--;
    }

    lapsed.tv_usec = second.tv_usec - first.tv_usec;
    lapsed.tv_sec  = second.tv_sec  - first.tv_sec;
    t = lapsed.tv_sec*1000000 + lapsed.tv_usec;

    printf("%lu,%lu - %lu,%lu = %ld,%ld\n",
           second.tv_sec, second.tv_usec,
           first.tv_sec,  first.tv_usec,
           lapsed.tv_sec, lapsed.tv_usec);

    return t;
}

ऐसा शायद इसलिए है क्योंकि घड़ी की टिक एक बहुत अच्छी तरह से परिभाषित इकाई नहीं है। आप इसे सेकंड में बदल सकते हैं और इसे डबल के रूप में प्रिंट कर सकते हैं:

time_in_seconds = (double)time_in_clock_ticks / (double)CLOCKS_PER_SEC;
printf("%g seconds", seconds);

CLOCKS_PER_SEC मैक्रो एक अभिव्यक्ति में फैलता है जो एक सेकंड में घड़ी की टिकों की संख्या का प्रतिनिधित्व करता है।





clock