В Python datetime.now()
может производить значение с большей точностью, чем time.time()
:
from datetime import datetime, timezone, timedelta
now = datetime.now(timezone.utc)
epoch = datetime(1970, 1, 1, tzinfo=timezone.utc) # use POSIX epoch
posix_timestamp_micros = (now - epoch) // timedelta(microseconds=1)
posix_timestamp_millis = posix_timestamp_micros // 1000 # or `/ 1e3` for float
Теоретически, time.gmtime(0)
(эпоха, используемая time.time()
) может отличаться от 1970
.
Предыдущие ответы указали на проверку конкретного #define, который будет присутствовать для вашего конкретного случая. Этот ответ относится к более общему случаю компиляции другого кода, независимо от того, доступна функция или нет.
Вместо того, чтобы пытаться делать все в самом файле C, это то, что действительно помогает скриптам configure. Если бы вы работали в Linux, я бы без колебаний указал вам на GNU Autotools . Я знаю, что для Windows доступны порты, по крайней мере, если вы используете Cygwin или MSYS, но я понятия не имею, насколько они эффективны.
Простой (и очень, очень уродливый) скрипт, который может работать, если у вас есть sh под рукой ( У меня нет удобной установки Windows, чтобы это проверить) выглядело бы примерно так:
#!/bin/sh
# First, create a .c file that tests for the existance of GetTickCount64()
cat >conftest.c <<_CONFEOF
#include <windows.h>
int main() {
GetTickCount64();
return 0;
}
_CONFEOF
# Then, try to actually compile the above .c file
gcc conftest.c -o conftest.out
# Check gcc's return value to determine if it worked.
# If it returns 0, compilation worked so set CONF_HASGETTICKCOUNT64
# If it doesn't return 0, there was an error, so probably no GetTickCount64()
if [ $? -eq 0 ]
then
confdefs='-D CONF_HASGETTICKCOUNT64=1'
fi
# Now get rid of the temporary files we made.
rm conftest.c
rm conftest.out
# And compile your real program, passing CONF_HASGETTICKCOUNT64 if it exists.
gcc $confdefs yourfile.c
Это должно быть достаточно легко для перевода на выбранный вами язык сценариев. Если вашей программе требуются дополнительные пути включения, флаги компилятора или что-то еще, обязательно добавьте необходимые флаги как в тестовую компиляцию, так и в настоящую компиляцию.
'yourfile.c' будет выглядеть примерно так:
#include <windows.h>
unsigned long long get_tick_count(void) {
#ifdef CONF_HASGETTICKCOUNT64
return GetTickCount64();
#else
return GetTickCount();
#endif
}
Вы можете достичь этого, используя определения препроцессора в заголовках Windows .
unsigned long long
get_tick_count(void)
{
#if WINVER >= 0x0600
return GetTickCount64();
#else
return GetTickCount();
#endif
}
Правильный способ справиться с подобными проблемами - это проверить, доступна ли функция, но это не может быть надежно сделано во время компиляции проекта. Вы должны добавить этап конфигурации, детали которого зависят от вашего инструмента сборки, и cmake, и scons, два кросс-платформенных инструмента сборки, предоставляют возможности. В принципе, это выглядит так:
/* config.h */
#define HAVE_GETTICKSCOUNT64_FUNC
А затем в своем проекте вы делаете:
#include "config.h"
#ifdef HAVE_GETTICKSCOUNT64_FUNC
....
#else
...
#endif
Хотя это выглядит очевидным образом, его гораздо легче поддерживать в долгосрочной перспективе. В частности, вам следует по возможности избегать зависимости от версий и вместо этого проверять возможности. Проверка версий быстро приводит к сложным, чередующимся условным выражениям, тогда как с помощью описанной выше техники все управляется из одного config.h, который, надеюсь, создается автоматически.
В scons и cmake у них будут тесты, которые запускаются автоматически, чтобы проверить, доступна ли функция, и определить переменную в config.h или нет, в зависимости от проверки. Основная идея состоит в том, чтобы отделить обнаружение / настройку возможностей от вашего кода .
Обратите внимание, что это может обрабатывать случаи, когда вам нужно создавать двоичные файлы, которые работают на разных платформах (скажем, запускаются в XP, даже если они созданы в Vista). Это просто вопрос изменения config.h. Если все сделано правильно, это просто вопрос изменения config.h (у вас может быть сценарий, который генерирует config.h на любой платформе, а затем собирает config.h для Windows XP, Vista и т. Д.). Я не думаю, что это вообще относится к unix.
Вы спрашиваете о C, но вопрос также помечен как C ++ ...
В C ++ вы бы использовали SFINAE см. аналогичные вопросы:
Можно ли написать шаблон для проверки существования функции?
Но используйте директивы препроцессора в Windows, если они есть.
Добрый день,
Разве NTDDI_VERSION не то, что вам нужно?
Обновление: Вы хотите проверить, имеет ли WINVER значение 0x0600. Если это так, то вы используете Vista.
Edit: Для семантической головки Pecker я имел в виду запуск компилятора в среде Vista. Вопрос касается только компиляции, вопрос касается только файлов заголовков, которые используются только во время компиляции. Большинство людей понимало, что предполагалось, что вы компилируете в среде Vista. Вопрос не имел отношения к поведению во время выполнения.
Если кто-то не работает под Vista и может компилировать для Windows XP?
Блин!
HTH
ура,
Компилятор Microsoft определит _WIN64 при компиляции для 64-битных машин.
http://msdn.microsoft.com/en-us/library/b0084kay%28VS.80%29. aspx
#if defined(_WIN64)
unsigned long long get_tick_count(void) { return GetTickCount64(); }
#else
unsigned long long get_tick_count(void) { return GetTickCount(); }
#endif
Если ваш код будет работать в операционных системах до Vista, вы не можете просто скомпилировать свои вызовы в GetTickCount64 (), потому что GetTickCount64 () не существует на машине XP.
Вам нужно определить во время выполнения, какую операционную систему вы используете, а затем вызвать правильную функцию. В общем, оба вызова должны быть в коде.
Теперь это может быть неверно в вашем случае, если вам действительно не нужно иметь возможность вызывать GetTickCount64 () на машинах Vista + и GetTickCount () на машинах XP . Вы можете просто вызвать GetTickCount () независимо от того, на какой ОС вы работаете. В документах нет никаких указаний на то, что они удаляют GetTickCount () из API.
Я также хотел бы указать, что, возможно, GetTickCount () вообще не подходит. В документации говорится, что он возвращает количество миллисекунд, но на самом деле точность функции даже близко не к 1 миллисекунде. В зависимости от машины (а во время выполнения AFAIK это невозможно узнать) точность может составлять 40 миллисекунд или даже больше. Если вам нужна точность в 1 миллисекунду, вы должны использовать QueryPerformanceCounter () . Фактически, действительно нет никаких практических причин не использовать QPC во всех случаях, когда вы все равно использовали бы GetTickCount ().
В документах нет никаких указаний на то, что они удаляют GetTickCount () из API.Я также хотел бы указать, что, возможно, GetTickCount () вообще не подходит. В документации говорится, что он возвращает количество миллисекунд, но на самом деле точность функции даже близко не к 1 миллисекунде. В зависимости от машины (а во время выполнения AFAIK это невозможно узнать) точность может составлять 40 миллисекунд или даже больше. Если вам нужна точность в 1 миллисекунду, вы должны использовать QueryPerformanceCounter () . Фактически, действительно нет никаких практических причин не использовать QPC во всех случаях, когда вы все равно использовали бы GetTickCount ().
В документах нет никаких указаний на то, что они удаляют GetTickCount () из API.Я также хотел бы указать, что, возможно, GetTickCount () вообще не подходит. В документации говорится, что он возвращает количество миллисекунд, но на самом деле точность функции даже близко не к 1 миллисекунде. В зависимости от машины (а во время выполнения AFAIK это невозможно узнать) точность может составлять 40 миллисекунд или даже больше. Если вам нужна точность в 1 миллисекунду, вы должны использовать QueryPerformanceCounter () . Фактически, действительно нет никаких практических причин не использовать QPC во всех случаях, когда вы все равно использовали бы GetTickCount ().
В документации говорится, что он возвращает количество миллисекунд, но на самом деле точность функции даже близко не к 1 миллисекунде. В зависимости от машины (а во время выполнения AFAIK это невозможно узнать) точность может составлять 40 миллисекунд или даже больше. Если вам нужна точность в 1 миллисекунду, вы должны использовать QueryPerformanceCounter () . Фактически, действительно нет никаких практических причин не использовать QPC во всех случаях, когда вы все равно использовали бы GetTickCount (). В документации говорится, что он возвращает количество миллисекунд, но на самом деле точность функции даже близко не к 1 миллисекунде. В зависимости от машины (а во время выполнения AFAIK это невозможно узнать) точность может составлять 40 миллисекунд или даже больше. Если вам нужна точность в 1 миллисекунду, вы должны использовать QueryPerformanceCounter () . Фактически, действительно нет никаких практических причин не использовать QPC во всех случаях, когда вы все равно использовали бы GetTickCount ().Выбор времени компиляции API на основе целевой версии Windows блокирует встроенный исполняемый файл для этой версии и более новых. Это распространенный метод для проектов с открытым исходным кодом, ориентированных на * nix, где предполагается, что пользователь настроит исходный код для своей платформы и скомпилирует его для установки.
В Windows это не обычный метод, потому что это не так. Как правило, можно с уверенностью предположить, что у конечного пользователя вообще будет компилятор, не говоря уже о том, чтобы иметь дело с тонкостями создания проекта для сборки.
Часто просто использование старого API, присутствующего во всех версиях Windows, является достаточный ответ. Это тоже просто: вы просто игнорируете существование нового API.
Когда этого недостаточно, вы используете LoadLibrary ()
и GetProcAddress ()
, чтобы попытаться разрешить новый символ во время выполнения. Если это не может быть решено, вы должны вернуться к старому API.
Вот возможная реализация. Он обнаруживает первый вызов и попытки загрузить библиотеку и разрешить имя «GetTickCount64»
. Во всех вызовах, если указатель на разрешенный символ не равен нулю, он вызывает его и возвращает результат. В противном случае он возвращается к старому API, приводя его возвращаемое значение в соответствие с типом оболочки.
unsigned long long get_tick_count(void) {
static int first = 1;
static ULONGLONG WINAPI (*pGetTickCount64)(void);
if (first) {
HMODULE hlib = LoadLibraryA("KERNEL32.DLL");
pGetTickCount64 = GetProcAddressA(hlib, "GetTickCount64");
first = 0;
}
if (pGetTickCount64)
return pGetTickCount64();
return (unsigned long long)GetTickCount();
}
Обратите внимание, что я использовал ... разновидности функций API, поскольку известно, что имя библиотеки и имя символа будут только ASCII ... при использовании этого метода для загрузки символов из установленной библиотеки DLL, которая может находиться в папке, названной с символами, отличными от ASCII,
Если вам нужно поддерживать до Vista, я бы придерживался только использования GetTickCount (). В противном случае вам придется реализовать код времени выполнения для проверки версии Windows и вызова GetTickCount () в версиях Windows до Vista и GetTickCount64 () в Vista и более поздних версиях. Поскольку они возвращают значения разного размера (ULONGLONG v DWORD), вам также потребуется отдельная обработка того, что они возвращают. Использование только GetTickCount () (и проверка на переполнение) будет работать в обеих ситуациях, тогда как использование GetTickCount64 (), когда оно доступно, увеличивает сложность вашего кода и удваивает объем кода, который вам нужно написать.
Придерживайтесь использования только GetTickCount (), пока не убедитесь, что ваше приложение больше не должно работать на компьютерах, предшествующих Vista.
Возможно, это хорошая замена для GetTickCount ()
double __stdcall
thetimer (int value)
{
static double freq = 0;
static LARGE_INTEGER first;
static LARGE_INTEGER second;
if (0 == value)
{
if (freq == 0)
{
QueryPerformanceFrequency (&first);
freq = (double) first.QuadPart;
}
QueryPerformanceCounter (&first);
return 0;
}
if (1 == value)
{
QueryPerformanceCounter (&second);
second.QuadPart = second.QuadPart - first.QuadPart;
return (double) second.QuadPart / freq;
}
return 0;
}