обработка переполнения clock_t из std :: clock ()

Вопрос относительно счетчика часов, созданного clock() из <ctime>. (Использование clock() рассматривается в других вопросах)

В моей системе clock_t - это псевдоним для long, максимальное значение которого согласно <climits> моего компилятора составляет 2147483647.

clock_t delay = clock_t(10) * CLOCKS_PER_SEC;
clock_t start = clock();
while(clock() - start < delay); //Note Semi-colon here makes this null statement
std::cout << clock();

Запустив это, я получаю примерно 10060. Что соответствует CLOCKS_PER_SEC, равному #defined (для моей системы) как 1000.

Итак, если есть 1000 CLOCKS_PER_SEC, тогда 2147483647/1000 = 2147483,647 секунды, что составляет примерно 24-25 дней.

Я не уверен, действительно ли это поведение определяется C ++, но я отмечаю, что обычное поведение при превышении лимита long заключается в переносе в отрицательный конец.

Например,

long m = long(2147483647);
std::cout << ++m << std::endl;

Выведет: -2147483648

Итак, предположим, что программа работала долгое время перед инициализацией start, а start случайно инициализирована значением 2147483647 (максимально возможное значение long).

На этом этапе я предполагаю, что мы начнем обертывать значения, возвращаемые clock(), чтобы получить такие значения, как -2147482649, поскольку мы снова приближаемся к 2147483647. Итак, мой исходный код, вероятно, займет очень много времени, чтобы завершить цикл, намного дольше, чем предполагалось.

Реальное поведение? Следует ли использовать этот стиль паузы только для задержек меньше определенной величины? Есть ли какая-то другая проверка, которая должна быть сделана, чтобы сделать это «безопасным»?


person user17753    schedule 13.08.2012    source источник


Ответы (3)


Что происходит, когда вы переполняете знаковый интегральный тип, определяется реализацией и может быть сигналом. И да, это означает, что clock() можно использовать только в течение фиксированного периода времени после начала вашего процесса, и, вероятно, только тогда, если реализация гарантирует, что первый вызов всегда будет возвращать 0 (случай для всех реализаций, о которых я знаю) .

person James Kanze    schedule 13.08.2012
comment
Формально поведение переполнения целочисленного типа со знаком является undefined поведением, а не определенным реализацией. Разница в том, что для последнего требуется, чтобы реализация документировала то, что она делает. Для первых все идет. - person Pete Becker; 13.08.2012
comment
@PeteBecker А, да. Это преобразование значения, которое не подходит, что определяется реализацией (но, по крайней мере, в C, может быть сигналом, определяемым реализацией). Я не знаю, почему я перепутал их. - person James Kanze; 13.08.2012

используйте: GetTickCount64 ();
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724411(v=vs.85).aspx

person kain64b    schedule 13.08.2012
comment
Этот ответ менее чем полезен, если рассматриваемый код не работает в Windows, о чем в вопросе не говорится. - person timelmer; 03.06.2017

Если clock_t определен как подписанный тип, то да, это ожидаемое поведение.

Если вас беспокоит перенос, вы всегда можете преобразовать значение clock_t в unsigned long (что означает, что вы предполагаете, что clock_t не шире, чем long), и вместо этого сохранить / сравнить это значение.

person David R Tribble    schedule 13.08.2012
comment
Если вы действительно хотите сделать это безопасно, C99 и C ++ 11 имеют uintmax_t, который является typedef для наибольшего беззнакового типа. Чуть менее безопасный подход - использовать unsigned long long; Преимущество uintmax_t состоит в том, что реализациям разрешено предоставлять более крупные целочисленные типы, и существует удаленная возможность, что clock_t будет использовать такой больший тип. Лично я бы использовал unsigned long, как предлагалось изначально. - person Pete Becker; 13.08.2012
comment
Привет, @PeteBecker, добро пожаловать в StackOverflow! Давно не виделись. - person David R Tribble; 13.08.2012
comment
Спасибо, @Loadmaster; слишком долго слонялся по группам новостей. - person Pete Becker; 13.08.2012
comment
Что еще хуже, я обнаружил, что clock() возвращает -1, если прошедшее время недоступно. Хотя -1 также может представлять допустимое время, поскольку clock_t является подписанным типом и не будет отображаться в беззнаковом приведении? - person user17753; 13.08.2012