0

I wrote some program to test my suspicions. It contains super-ultra-reliable function, on my mind :), called less to compare integral numbers. For some combinations of types it produces results that differ from the results, which gives C++. When this happens it gives false, that you can see on the screen.

#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; 
}

I compile (bash s.sh 2>&1 | tee s.log) the program using the following script:

#!/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 

As a result (s.log) script gives the following:

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  

As you can see the results are the same (for x32 and x64 platforms). And some of the tests have failed. Why is this happening? My program is wrong or my knowledge about C++ is little?

4

1 回答 1

2

您正在测试基本operator <功能是否与您的功能相同less。它不是。

您的函数考虑了有符号/无符号不匹配,并给出了数学上正确的答案。

当有符号/无符号不匹配时,基本的 C++ 运算符会将有符号值转换为无符号值。

于 2013-02-10T19:58:09.033 回答