I tried creating a Stopwatch struct whose purpose is to measure time using the Windows QueryPerformanceCounter() function, and if it does not exist or is not supported, it falls back to using clock() in time.h.
Unfortunately a Linker error is taking place as follows:
Error LNK2001: unresolved external symbol "private: static struct Stopwatch::StopwatchInitializer Stopwatch::platformInfo" (?platformInfo@Stopwatch@@0UStopwatchInitializer@1@A) in Main.obj
When I change platformInfo
to non-static, the application works, but if marked static
, it doesn't.
My intention is to leave it static so that it is initialized only once, but the Linker is not cooperating.
Why is that? Here is my code:
StdAfx.h:
#pragma once
#include "time.h"
#ifdef _WIN32
#include "windows.h"
#endif
//A stopwatch function provider that offers clock tick accuracy
struct Stopwatch {
//holds the platform data required to initialize the stopwatch
private:
struct StopwatchInitializer {
public:
double nanosecondsPerTick;
bool isHighResolution;
StopwatchInitializer() {
#ifdef _WIN32
LARGE_INTEGER value;
isHighResolution = !!QueryPerformanceFrequency(&value);
nanosecondsPerTick = isHighResolution ? 1000000000.0 / value.QuadPart : 1000000000.0 / CLOCKS_PER_SEC;
#elif
isHighResolution = false;
nanosecondsPerTick = 1000000000.0 / CLOCKS_PER_SEC;
#endif
}
};
//static single instance of the StopwatchInitializer instance
//here is the error though
static const StopwatchInitializer platformInfo;
double startTimeStamp, elapsed;
bool isRunning;
public:
//Initializes the stopwatch.
Stopwatch() {
elapsed = 0.0;
startTimeStamp = 0.0;
isRunning = false;
}
//Initializes the stopwatch with the specified pre-elapsed ticks.
Stopwatch(double preElapsedTicks) {
elapsed = preElapsedTicks;
startTimeStamp = 0.0;
isRunning = false;
}
//Gets the current time in platform-specific ticks.
double getTimeStamp() {
#ifdef _WIN32
if (platformInfo.isHighResolution) {
LARGE_INTEGER num;
QueryPerformanceCounter(&num);
return (double) num.QuadPart;
} else
return (double) clock();
#elif
return (double) clock();
#endif
}
//Starts or resumes the stopwatch.
void start() {
if (isRunning)
return;
isRunning = true;
startTimeStamp = getTimeStamp();
}
//Stops the stopwatch.
void stop() {
if (isRunning) {
isRunning = false;
elapsed += getTimeStamp() - startTimeStamp;
}
}
//Gets whether the stopwatch is running
int getIsRunning() {
return isRunning;
}
//Sets whether the stopwatch is running (boolean value).
void setIsRunning(bool value) {
if (value)
start();
else
stop();
}
//Gets the current elapsed ticks.
double getElapsedTicks() {
return isRunning ? (elapsed - startTimeStamp) + getTimeStamp() : elapsed;
}
//Gets the elapsed time in fortnights.
double getElapsedFortnights() {
return (platformInfo.nanosecondsPerTick * 0.00000000000000082671957671957672) * getElapsedTicks();
}
//Gets the elapsed time in weeks.
double getElapsedWeeks() {
return (platformInfo.nanosecondsPerTick * 0.00000000000000165343915343915344) * getElapsedTicks();
}
//Gets the elapsed time in days.
double getElapsedDays() {
return (platformInfo.nanosecondsPerTick * 0.00000000000001157407407407407407) * getElapsedTicks();
}
//Gets the elapsed time in hours.
double getElapsedHours() {
return (platformInfo.nanosecondsPerTick * 0.00000000000027777777777777777777) * getElapsedTicks();
}
//Gets the elapsed time in minutes.
double getElapsedMinutes() {
return (platformInfo.nanosecondsPerTick * 0.00000000001666666666666666666666) * getElapsedTicks();
}
//Gets the elapsed time in seconds.
double getElapsedSeconds() {
return (platformInfo.nanosecondsPerTick * 0.000000001) * getElapsedTicks();
}
//Gets the elapsed time in milliseconds.
double getElapsedMilliseconds() {
return (platformInfo.nanosecondsPerTick * 0.000001) * getElapsedTicks();
}
//Gets the elapsed time in microseconds.
double getElapsedMicroseconds() {
return (platformInfo.nanosecondsPerTick * 0.001) * getElapsedTicks();
}
//Gets the elapsed time in nanoseconds.
double getElapsedNanoseconds() {
return platformInfo.nanosecondsPerTick * getElapsedTicks();
}
//Resets the elapsed time.
void reset() {
elapsed = 0.0;
isRunning = false;
startTimeStamp = 0.0;
}
//Resets the elapsed time to the specified platform-specific ticks.
void reset(double ticks) {
elapsed = ticks;
isRunning = false;
startTimeStamp = 0.0;
}
//Resets the stopwatch and restarts it.
void restart() {
elapsed = 0.0;
isRunning = true;
startTimeStamp = getTimeStamp();
}
//Resets the stopwatch to specified platform-specific ticks and restarts it.
void restart(double ticks) {
elapsed = ticks;
isRunning = true;
startTimeStamp = getTimeStamp();
}
//Converts nanoseconds to platform-specific ticks.
double convertToTicks(double nanoseconds) {
return nanoseconds / platformInfo.nanosecondsPerTick;
}
//Converts platform-specific ticks to nanoseconds.
double convertToNanoseconds(double ticks) {
return ticks * platformInfo.nanosecondsPerTick;
}
};
Main.h:
#include "stdafx.h"
#include "stdio.h"
//entry point
int main() {
Stopwatch stopwatch;
int x;
double value = 100002030.0;
stopwatch.start();
for (x = 0; x < 100000000; x++)
value /= 2.2;
printf("Division: %fms, value: %f", stopwatch.getElapsedMilliseconds(), value);
value = 100002030.0;
stopwatch.restart();
for (x = 0; x < 100000000; x++)
value *= 0.45454545454;
printf("\nMultiplication: %fms, value: %f", stopwatch.getElapsedMilliseconds(), value);
scanf_s("");
}