0

私は自分の疑惑をテストするためにいくつかのプログラムを書きました。これには、整数を比較するため:)に呼び出される、超信頼性の高い関数が含まれています。lessタイプのいくつかの組み合わせでは、結果とは異なる結果が生成され、C++が得られます。これが発生すると、画面に表示されるfalseが表示されます。

#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 ++に関する知識が少ないですか?

4

1 に答える 1

2

operator <基本的な機能があなたの機能と同じかどうかをテストしていますless。そうではありません。

関数は符号付き/符号なしの不一致を考慮し、数学的に正しい答えを提供します。

基本的な C++ 演算子は、符号付き/符号なしの不一致がある場合、符号付きの値を符号なしの値に変換します。

于 2013-02-10T19:58:09.033 に答える