ما هي الطريقة الصحيحة لاستخدام printf لطباعة clock_t؟
سؤال
أنا أستخدم حاليا صريحا unsigned long long
واستخدام %llu
لطباعة ذلك، ولكن منذ size_t
لديه %z
محدد، لماذا لا clock_t
لديك واحدة؟
ليس هناك حتى ماكرو لذلك. ربما أستطيع أن أفترض أنه على نظام X64 (OS و CPU) size_t
هو 8 بايت في الطول (وحتى في هذه الحالة، قدموا %z
)، لكن ماذا عن clock_t
?
المحلول
يبدو أن هناك ليست هناك طريقة مثالية. جذر المشكلة هو ذلك clock_t
يمكن أن يكون إما عدد صحيح أو نقطة عائمة.
Clock_t يمكن أن يكون نوع نقطة عائمة
كما يذكر باستين لونارد ل posix (الذهاب فوقه)، C99 N1256 مسودة 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
لأنواع النقطة العائمة: كيفية الحصول على أكبر نوع بيانات النقطة العائمة الدقة من الانتقاد ومحددات طباعة؟ لذلك إذا كان نوع النقطة العائمة أكبر يخرج غدا، فيمكن استخدامه وكسر تطبيقك.إذا
clock_t
هو عدد صحيح، يلقي المقصود المعروف جيدا لاستخدام أقرب تعويم ممكن. قد تفقد الدقة، لكن الأمر لا يهم بالمقارنة مع القيمة المطلقة، ولن يحدث فقط كميات هائلة من الزمن، على سبيل المثالlong int
في x86 هو تعويم 80 بت مع 144 بت ذات أهمية، وهو الملايين من السنوات في ثوان.
الذهاب فوق Ummentad. من قال شيئا مشابها.
إذا كنت تفترض أنه عدد صحيح، فاستخدم٪ ju و uintmax_t
برغم من unsigned long long
هو حاليا أكبر نوع عدد صحيح قياسي ممكن:
- يمكن لأحد أن يخرج في المستقبل
- المعيار بالفعل يسمح صراحة بأنواع أخرى محددة في التنفيذ (Kudos ToFuzXXL) و
clock_t
يمكن أن يكون واحد منهم
لذلك من الأفضل أن Typecast لأكبر نوع عدد صحيح غير محتمل ممكن:
#include <stdint.h>
printf("%ju", (uintmax_t)(clock_t)1);
uintmax_t
مضمون للحصول على حجم أكبر حجم صحيح ممكن على الجهاز.
uintmax_t
ومحدد طباعة %ju
تم تقديمها في C99 و GCC على سبيل المثال تنفذها.
ككافأة، هذا يحل مرة واحدة وعلى الرغم من سؤال كيفية موثوق printf
أنواع عدد صحيح (وهذا لسوء الحظ ليس هو الحال بالضرورة clock_t
).
ما يمكن أن يحدث خطأ إذا كان مزدوج:
- إذا كان كبيرا جدا لتناسب عدد صحيح، سلوك غير محدد
- أصغر بكثير من 1، سوف تحصل على تقريب إلى 0 ولن ترى أي شيء
نظرا لأن هذه العواقب أكثر صرامة بكثير من عدد صحيح لتحويل التعويم، فمن المحتمل أن يكون استخدام تعويم فكرة أفضل.
على Glibc 2.21 إنه عدد صحيح
يقول الدليل أن استخدام double
هي فكرة أفضل:
على أنظمة GNU / Linux و GNU / HURD، Clock_t تعادل Long Int و Clocks_per_sec قيمة عدد صحيح. ولكن في أنظمة أخرى، يمكن أن تكون كل من Clock_t و Clubsss_per_secs_per_sec من الماكرو كلا من أنواع عدد صحيح أو فينتيرز. تؤكد القيم الزمنية التي تمزقها وحدة المعالجة المركزية المزدوجة، كما هو الحال في المثال أعلاه، أن العمليات مثل الحساب والطباعة تعمل بشكل صحيح وباستخدامها بغض النظر عن التمثيل الأساسي.
في Glibc 2.21:
clock_t
يكونlong int
:- الوقت / الوقت يحددها إلى
__clock_t
- البتات / أنواع يحددها إلى
__CLOCK_T_TYPE
- بت / ينضج يحددها إلى
__SLONGWORD_TYPE
- البتات / أنواع يحددها إلى
long int
- الوقت / الوقت يحددها إلى
clock()
في لينكس يتم تنفيذها معsys_clock_gettime
:- SYSDEPS / UNIX / SYSV / Linux / Clock.c المكالمات
__clock_gettime
- sysdeps / يونيكس / clock_gettime.c المكالمات
SYSDEP_GETTIME_CPU
- SYSDEPS / UNIX / SYSV / Linux / Clock_gettime.c المكالمات
SYSCALL_GETTIME
التي تقدم أخيرا مكالمة نظام مضمنة
man clock_gettime
, ، يخبرنا أنه يعودstruct timespec
التي في دول مجلس التعاون الخليجيlong int
مجالات.وبالتالي فإن التنفيذ الأساسي يعيد الأعداد الصحيحة حقا.
- SYSDEPS / UNIX / SYSV / Linux / Clock.c المكالمات
أنظر أيضا
نصائح أخرى
بقدر ما أعرف، الطريقة التي تفعلها هي الأفضل. ماعادا هذا clock_t
قد يكون نوع حقيقي:
time_t
وclock_t
يجب أن يكون عدد صحيح أو حقيقي العائمة.
http://www.opengroup.org/onlinepubs/009695399/basedefs/sys/types.h.html
ربما لأن علامات الساعة ليست وحدة محددة للغاية. يمكنك تحويله إلى ثوان وطباعته كمضاعف:
time_in_seconds = (double)time_in_clock_ticks / (double)CLOCKS_PER_SEC;
printf("%g seconds", seconds);
يتوسع الماكرو Clocks_per_sec إلى تعبير يمثل عدد علامات الساعة في الثانية.
يتعين على قيادة C إسكيع مجموعة واسعة من البنيات، مما يجعل من المستحيل جعل أي ضمانات أخرى جانبا من حقيقة أن نوع الساعة الداخلي هو حسابي.
في معظم الحالات، أنت مهتم بفواصل زمنية، لذلك قمت بتحويل الفرق في علامات الساعة إلى مللي ثانية. أ unsigned long
كبير بما يكفي لتمثيل الفاصل الزمني لما يقرب من 50 يوما حتى لو كان 32 بت، لذلك يجب أن يكون كبيرا بما يكفي لمعظم الحالات:
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;
}