2016-01-22 2 views
3
#include <string> 
#include <iostream> 
using namespace std; 

int main() 
{ 
    string haystack = "aaa"; 
    string needle = "aaaa"; 
    int i = 0; 
    if(i <= haystack.size() - needle.size()) 
    cout<<"why 0<-1?"<<endl; 
    return 0; 
} 

Выход: почему 0 < -1? Нажмите любую клавишу продолжить ...Почему C++ string1.size() минус string2.size() получил неправильный ответ?

Почему мы получили этот выход? Я думаю, что «если» оператор не должен быть выполнен, причина 0 больше 3-4 = -1. Спасибо!

+1

Посмотрите на тип возвращаемого типа 'string :: size'. – ZDF

+0

@ZDF спасибо! Я знаю, что допустил ошибку. – jianhui

+0

Почему бы прямо не сравнить два значения, которые вы хотите сравнить? 'if (haystack.size() e0k

ответ

9

Возвратный тип std::string::size - std::size_t.

Это неподписанный номер. Поэтому, поскольку вычитание приводит к отрицательному значению, it will wrap around основано на two's complement, в результате чего очень большое число намного превышает 0.

+0

Спасибо. Чем -1 превращается в без знака 0xFFFFFFFF. – jianhui

+0

Остерегайтесь, на 64-битном процессоре он, вероятно, превратится в 0xFFFFFFFFFFFFFFFF. –

2

По историческим причинам стандартная библиотека обычно использует size_t, которая является неподписанным номером, в качестве результата типа функций размера. Исключением является std::count. Но std::string::size() является одним из size_t функций,

Поскольку язык гарантирует модульную арифметику для выражения без знака типа, вы получите наматывается вокруг, где -1 становится наибольшее значение без знака типа.


Другой и IMO более очевидно глупо следствием является то, что

std::string("Hello").size() < -1 

является гарантировано. Просто чистая бессмыслица, как текст исходного кода, когда можно вспомнить, что целью исходного кода высокого уровня является более четкое общение с людьми.


Чтобы избежать этой путаницы можно определить логическую подписанную Size типа в качестве псевдонима для ptrdiff_t (который является знаковым типом аналог size_t) и поддакивать функции размера static_size, n_items и length, плюс клетчатой ​​is_empty, как следующим образом:

sizes_and_lengths.hpp
#pragma once 
// p/cppx/core_language_support/sizes_and_lengths.hpp 
// Copyright © Alf P. Steinbach 2015. Boost Software License 1.0. 

#include <p/cppx/core_language_support/basic_types.hpp> 
#include <p/cppx/core_language_support/overloading.hpp>    // cppx::(Object_argument etc.) 
#include <p/cppx/core_language_support/type_builders.hpp>   // cppx::(Ptr_, Ref_, Array_of_, ...) 
#include <p/cppx/core_language_support/tmp/If_.hpp>     // cppx::(If_, Is_) 
#include <p/cppx/core_language_support/tmp/type_relationships.hpp> // cppx::Is_convertible_to_ 

#include <string>   // std::basic_string 
#include <utility>   // std::declval 

namespace progrock{ namespace cppx{ 
    // These templates use size_t to accommodate g++, which has bug in this area. 

    // static_size() 
    // Static capacity of a collection. 

    template< class Type, size_t n > 
    constexpr 
    auto static_size(In_ref_<Raw_array_of_<n, Type>>) 
     -> Size 
    { return n; } 

    template< class Type, size_t n > 
    constexpr 
    auto static_size(In_ref_<Array_of_<n, Type>>) 
     -> Size 
    { return n; } 

    template< size_t n > 
    constexpr 
    auto static_size(In_ref_<std::bitset<n>>) 
     -> Size 
    { return n; } 


    // n_items() & is_empty() 
    // Right-typed (signed integer) dynamic size of a collection. 

    template< class Type > 
    auto n_items(In_ref_<Type> o) 
     -> Size 
    { return o.size(); } 

    template< size_t n > 
    auto n_items(In_ref_<std::bitset<n>> o) 
     -> Size 
    { return o.count(); }  // Corresponds to std::set<int>::size() 

    namespace impl { 
     using std::declval; 

     template< class Type > 
     constexpr 
     auto has_std_empty_checker(...) 
      -> bool 
     { return false; } 

     template< class Type > 
     constexpr 
     auto has_std_empty_checker(int) 
      -> If_< 
       Is_<bool, decltype(declval<const Type>().empty())>, // CFINAE 
       Then_<bool>            // SFINAE 
       > 
     { return true; } 

     struct Using_empty_method 
     { 
      template< class Type > 
      auto is_empty(In_ref_<Type> o) const 
       -> bool 
      { return o.empty(); } 
     }; 

     struct Using_n_items_function 
     { 
      template< class Type > 
      auto is_empty(In_ref_<Type> o) const 
       -> bool 
      { return (n_items(o) == 0); } 
     }; 

    } // namespace impl 

    template< class Type > 
    constexpr 
    auto has_std_empty_checker() 
     -> bool 
    { return impl::has_std_empty_checker<Type>(42); } 

    template< class Type > 
    auto is_empty(In_ref_<Type> o) 
     -> bool 
    { 
     using Impl = Ifc_< 
      has_std_empty_checker<Type>(), 
      Then_<impl::Using_empty_method>, 
      Else_<impl::Using_n_items_function> 
      >; 
     return Impl().is_empty(o); 
    } 

    template< size_t n > 
    auto is_empty(In_ref_<std::bitset<n>> bits) 
     -> bool 
    { return bits.none(); } 


    // length() & length_of_literal() & is_empty 
    // Lengths of strings. 

    template< class Char, size_t n > 
    constexpr 
    auto length_of_literal(In_ref_<Raw_array_of_<n, Char>>) // "length" wraps this. 
     -> Size 
    { return n - 1; } 

    template< class Type > 
    auto length(Object_argument, In_ref_<Type> s) 
     -> Size 
    { return s.length(); } 

    template< class Char 
     , class Enabled_ = If_< Is_in_< Character_types, Char > > 
     > 
    auto length(Pointer_argument, In_value_<Ptr_<const Char>> s) 
     -> Size 
    { 
     auto p = s; 
     while(*p != 0) { ++p; } 
     return p - s; 
    } 

    template< class Char, size_t n 
     , class Enabled_ = If_< Is_in_< Character_types, Char > > 
     > 
    auto constexpr length(Array_argument, In_ref_<Raw_array_of_<n, Char>> a) 
     -> Size 
    { return length_of_literal(a); } 

    template< class Type > 
    auto length(In_ref_<Type> o) 
     -> Size 
    { return length(Arg_kind_<Type>(), o); } 

    template< class Char 
     , class Enabled_ = If_< Is_in_< Character_types, Char > > 
     > 
    auto is_empty(In_value_<Ptr_<const Char>> s) 
     -> bool 
    { return (*s == 0); } 

}} // namespace progrock::cppx 

Если вы хотите использовать этот код, частично или в целом, реж Кроме того, не принося вспомогательные файлы из cppx library, вам придется перевести, например. In_ - тип, который вы предпочитаете для логического аргумента и т. Д. Библиотека cppx - это очень важная вещь, но ее можно использовать как есть. Он предоставляет такие вещи, как вышесказанное, те самые основы, которые каким-то образом пропустили стать частью стандартной библиотеки или даже были предложены.

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