I am making a simple test program to test my library. I wanted to make some easy to use operator overloads for struct timespec
, which I did. One of them is to calculate the time difference in milliseconds:
double operator-(const timespec& lhs, const timespec& rhs)
{
auto diff_seconds = (static_cast<double>(lhs.tv_sec) - static_cast<double>(rhs.tv_sec));
auto diff_nseconds = (static_cast<double>(lhs.tv_nsec) - static_cast<double>(rhs.tv_nsec));
auto diff_sec_to_ms = diff_seconds * 1000.0;
auto diff_nsec_to_ms = diff_nseconds / 1000000.0;
return diff_sec_to_ms + diff_nsec_to_ms;
}
However, when compiling in with any level of optimization (>-O1
), gcc complains:
error: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C2 -+ C1 [-Werror=strict-overflow]
while in no-optimization (-O0
) mode this is not the case. I would like to know why gcc complains here. I use the following compiler flags, including -Wstrict-overflow=5
, which I understand is strict and can cause false positives. I would like to know the reasoning behind this false positive.
-pedantic -Wall -Wextra -Wcast-align -Wcast-qual
-Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2
-Winit-self -Wlogical-op -Wmissing-declarations -Wundef
-Wmissing-include-dirs -Wnoexcept -Wold-style-cast
-Woverloaded-virtual -Wredundant-decls -Wshadow
-Wsign-conversion -Wsign-promo -Wstrict-null-sentinel
-Wstrict-overflow=5 -Wswitch-default -Werror -Wno-unused
A sample program to duplicate:
#include <ctime>
#include <iostream>
bool operator <(const timespec& lhs, const timespec& rhs);
bool operator >(const timespec& lhs, const timespec& rhs);
bool operator <=(const timespec& lhs, const timespec& rhs);
double operator-(const timespec& lhs, const timespec& rhs); // PROBLEMATIC FUNCTION <------------
int main(int argc, char** argv){
struct timespec start_time{}, end_time{}, curr_time{};
clock_gettime(CLOCK_REALTIME, &start_time);
end_time.tv_sec = start_time.tv_sec + 10; // Run for 10 seconds
end_time.tv_nsec = 0;
curr_time = start_time;
while(curr_time <= end_time){
std::cout << curr_time - start_time << std::endl;
clock_gettime(CLOCK_REALTIME, &curr_time);
curr_time.tv_nsec += 1000000ll * 250; // Every 250 ms sample the sensor
if(curr_time.tv_nsec > 1000000000ll){
curr_time.tv_nsec -= 1000000000ll;
curr_time.tv_sec += 1;
}
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &curr_time, nullptr);
}
return 0;
}
bool operator <(const timespec& lhs, const timespec& rhs)
{
if (lhs.tv_sec == rhs.tv_sec)
return lhs.tv_nsec < rhs.tv_nsec;
else
return lhs.tv_sec < rhs.tv_sec;
}
bool operator >(const timespec& lhs, const timespec& rhs){
return not operator<(lhs, rhs);
}
bool operator <=(const timespec& lhs, const timespec& rhs){
if (lhs.tv_sec == rhs.tv_sec)
return lhs.tv_nsec <= rhs.tv_nsec;
else
return lhs.tv_sec < rhs.tv_sec;
}
// PROBLEMATIC FUNCTION <------------
double operator-(const timespec& lhs, const timespec& rhs)
{
auto diff_seconds = (static_cast<double>(lhs.tv_sec) - static_cast<double>(rhs.tv_sec));
auto diff_nseconds = (static_cast<double>(lhs.tv_nsec) - static_cast<double>(rhs.tv_nsec));
auto diff_sec_to_ms = diff_seconds * 1000.0;
auto diff_nsec_to_ms = diff_nseconds / 1000000.0;
return diff_sec_to_ms + diff_nsec_to_ms;
}
Compile without errors / warnings:
g++ main.cpp -o test -Wstrict-overflow=5 -Werror -O0
Compile with errors / warnings:
g++ main.cpp -o test -Wstrict-overflow=5 -Werror -O1