2013-02-10 3 views
0

Я написал программу для проверки своих подозрений. Он содержит супер-сверхнадежную функцию, на мой взгляд, :), называемую 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++ немного?

+0

Вы спрашиваете, почему результаты одинаковы или почему некоторые тесты не удались? –

+0

Почему некоторые тесты потерпели неудачу? – Orient

ответ

2

Вы проверяете, действуют ли основные функции operator < так же, как и ваша функция less. Это не.

Ваша функция учитывает несоответствие подписанного/неподписанного и дает математически правильный ответ.

Основополагающий оператор C++ преобразует знаковое значение в значение без знака, когда есть несоответствие с подписью/без знака.

+0

Он делает это, выполняя расширение типа? – Orient

+0

Существует множество существующих вопросов о том, как интеграционное преобразование работает на C++. –

+1

Он будет интерпретировать биты знакового значения, как если бы он был без знака. Вот почему вы получали предупреждения. Предупреждения говорят вам * «Это быстро, но это может быть не то, что вы хотите» * –

Смежные вопросы