为什么c ++ string1.size()减去string2.size()得到了错误的答案?

时间:2016-01-22 18:01:56

标签: c++ string

#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? 按任意键继续......

为什么我们得到这个输出?我想&#34;如果&#34;不应该执行语句因为0大于3-4 = -1。 谢谢!

2 个答案:

答案 0 :(得分:10)

std::string::size的返回类型为std::size_t

这是 unsigned 类型。因此,由于您的减法会产生一个负值,it will wrap around基于two's complement,因此会产生远大于0的非常大的数字。

答案 1 :(得分:2)

由于历史原因,标准库通常使用size_t unsigned 类型)作为size函数的结果类型。 std::count是一个例外。但是std::string::size()size_t函数中的一部分,

由于该语言保证了无符号类型表达式的模运算,因此在-1成为无符号类型的最大值时会得到回绕。

另一个和IMO更明显的愚蠢后果是

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

保证。只是纯粹的废话作为源代码文本,当人们回忆起高级源代码的目的是为了更清楚地与人沟通。

为了避免这种混乱,您可以将逻辑签名的Size类型定义为ptrdiff_t的别名(与size_t对应的签名类型)和同上大小的函数{{1} },static_sizen_items以及检查器length,如下所示:

sizes_and_lengths.hpp
is_empty

如果您想部分或全部使用此代码,而不直接从cppx library引入支持文件,则必须翻译,例如#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库只是一个非常重要的事情,但它已经可以使用了。它提供了如上所述的东西,不知何故错过了成为标准库的一部分,甚至被提议的基础知识。