Я написал программу для проверки своих подозрений. Он содержит супер-сверхнадежную функцию, на мой взгляд, :)
, называемую less
для сравнения целочисленных чисел. Для некоторых комбинаций типов он дает результаты, которые отличаются от результатов, что дает C++. Когда это происходит, это дает ложь, которую вы можете видеть на экране.сравнить целые числа с разной подписью
#include <iostream>
#include <iomanip>
#include <type_traits>
#include <limits>
#include <typeinfo>
#include <cstdlib>
#pragma GCC diagnostic ignored "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wtype-limits"
template< typename T, typename U >
inline
bool less(T const & lhs, U const & rhs)
{
if (std::is_signed<T>::value && std::is_unsigned<U>::value) {
if (lhs < 0) {
return true;
} else if (rhs > std::numeric_limits<T>::max()) {
return true;
} else {
return static_cast<T>(lhs) < rhs;
}
} else if (std::is_unsigned<T>::value && std::is_signed<U>::value) {
if (rhs < 0) {
return false;
} else if (lhs > std::numeric_limits<T>::max()) {
return false;
} else {
return lhs < static_cast<T>(rhs);
}
} else {
return lhs < rhs;
}
}
#pragma GCC diagnostic warning "-Wtype-limits"
#pragma GCC diagnostic warning "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wtype-limits"
template< typename U, typename S >
void test()
{
std::cout << typeid(U).name() << " vs " << typeid(S).name() << std::endl;
static_assert(std::is_unsigned<U>::value && std::is_signed<S>::value, "signedness violated");
static_assert(sizeof(U) != sizeof(S), "size should not be the same");
U const x(std::numeric_limits<U>::max() - 2);
S const y(-1);
S const z(std::numeric_limits<S>::min());
std::cout << std::boolalpha << (less(x, y) == (x < y)) << std::endl
<< std::boolalpha << (less(y, x) == (y < x)) << std::endl
<< std::boolalpha << (less(y, z) == (y < z)) << std::endl
<< std::boolalpha << (less(z, y) == (z < y)) << std::endl
<< std::boolalpha << (less(x, z) == (x < z)) << std::endl
<< std::boolalpha << (less(z, x) == (z < x)) << std::endl
<< std::endl;
}
#pragma GCC diagnostic warning "-Wtype-limits"
#pragma GCC diagnostic warning "-Wsign-compare"
int main()
{
using namespace std;
test< uint8_t, int16_t >();
test< uint8_t, int32_t >();
test< uint8_t, int64_t >();
test< uint16_t, int8_t >();
test< uint16_t, int32_t >();
test< uint16_t, int64_t >();
test< uint32_t, int8_t >();
test< uint32_t, int16_t >();
test< uint32_t, int64_t >();
test< uint64_t, int8_t >();
test< uint64_t, int16_t >();
test< uint64_t, int32_t >();
return EXIT_SUCCESS;
}
компилировать (bash s.sh 2>&1 | tee s.log
) программу с помощью следующего сценария:
#!/usr/bin/env sh
set -o errexit
set -o verbose
g++ -std=gnu++11 -m64 s.cpp -o s64
g++ -std=gnu++11 -m32 s.cpp -o s32
MINGWDIR=/c/mingw64
PATH=/usr/bin:${MINGWDIR}/bin:/c/Windows/system32:${MINGWDIR}/x86_64-w64-mingw32/lib32 ./s64 2>&1 | tee s64.log | grep -c false
PATH=/usr/bin:${MINGWDIR}/bin:/c/Windows/system32:${MINGWDIR}/x86_64-w64-mingw32/lib32 ./s32 2>&1 | tee s32.log | grep -c false
diff s32.log s64.log
В результате (s.log
) сценарий дает следующее:
g++ -std=gnu++11 -m64 s.cpp -o s64
g++ -std=gnu++11 -m32 s.cpp -o s32
MINGWDIR=/c/mingw64
PATH=/usr/bin:${MINGWDIR}/bin:/c/Windows/system32:${MINGWDIR}/x86_64-w64-mingw32/lib32 ./s64 2>&1 | tee s64.log | grep -c false
10
PATH=/usr/bin:${MINGWDIR}/bin:/c/Windows/system32:${MINGWDIR}/x86_64-w64-mingw32/lib32 ./s32 2>&1 | tee s32.log | grep -c false
10
diff s32.log s64.log
Как вы можете видеть результаты (для x32 и x64 платформ). И некоторые из тестов потерпели неудачу. Почему это происходит? Моя программа неправильная или мои знания о C++ немного?
Вы спрашиваете, почему результаты одинаковы или почему некоторые тесты не удались? –
Почему некоторые тесты потерпели неудачу? – Orient