【问题标题】:Why does string::compare return an int?为什么 string::compare 返回一个 int?
【发布时间】:2013-02-26 15:01:30
【问题描述】:

为什么 string::compare 返回 int 而不是像 shortchar 这样的较小类型?我的理解是这个方法只返回-1、0或1。

第二部分,如果我要设计一个比较方法来比较Foo 类型的两个对象并且我只想返回-1、0 或1,那么使用shortchar 通常是个好主意?

编辑:我已得到更正,string::compare 不返回 -1、0 或 1,它实际上返回值 >0、

似乎答案是粗略的,没有理由返回小于 int 的类型,因为返回值是“右值”,而那些“右值”不会从小于 int 类型(4 字节)中受益.此外,许多人指出,大多数系统的寄存器可能会是int 的大小,因为无论你给它们一个 1、2 还是 4 字节值,这些寄存器都会被填充,没有真正的优势返回一个较小的值。

编辑 2:事实上,当使用较小的数据类型(如对齐、屏蔽等)时,看起来可能会有额外的处理开销。普遍的共识是,存在较小的数据类型是为了在处理大量数据时节省内存,就像数组的情况一样。

今天学到了一些东西,再次感谢大家!

【问题讨论】:

  • 我认为如果有更具体的类型可以用于此,那会更好。一个只包含 Ada95 样式的 -1、0 和 1。
  • 您链接到的 string::compare() 的文档明确指出返回值是 0 -not- -1、0 和 1。
  • 使用shortchar 代替int 有什么好处?大多数体系结构会将函数的返回值存储在寄存器中,intshortchar 一样适合寄存器。并且将char 用于数字类型总是一个坏主意,尤其是当您需要保证正确处理有符号值时。
  • Obvlious 船长,你的名字和评论……简直是无价之宝。
  • 使用char 是个坏主意,因为在char 未签名的平台上,如果返回值小于零,代码检查将失败。

标签: c++


【解决方案1】:

首先,规范是它将返回一个值 less 大于、等于或大于0,不一定是-11。 其次,返回值是右值,服从积分 促销,所以退回任何较小的东西是没有意义的。

在 C++ 中(就像在 C 中一样),每个表达式要么是一个右值,要么是一个 左值。从历史上看,这些术语指的是左值 出现在分配的左侧,其中右值只能 出现在右侧。今天,一个简单的近似 非类类型是左值在内存中具有地址, 右值没有。因此,您不能获取右值的地址, 和 cv 限定符(条件“访问”)不适用。在 C++ 术语,没有类类型的右值是纯的 值,而不是对象。函数的返回值是 右值,除非它具有引用类型。 (非类类型 fit in a register 几乎总是在寄存器中返回, 例如,而不是在内存中。)

对于类类型,问题有点复杂,因为 事实上,您可以在右值上调用成员函数。这 意味着右值实际上必须有地址,对于this 指针,并且可以是 cv 限定的,因为 cv 限定 在过载解决中发挥作用。最后,C++11 介绍了 几个新的区别,以支持右值引用; 这些也主要适用于类类型。

整数提升是指当整数类型 小于int 在表达式中用作右值,在 大多数情况下,它们将被提升为int。所以即使 我有一个声明为short a, b; 的变量,在表达式a + b 中,在添加之前ab 都被提升为int 发生。同样,如果我写a < 0,则比较完成 在a 的值上,转换为int。在实践中,有 很少有这种情况会产生影响,至少在 2 对整数算术换行的机器进行补码(即 今天,除了极少数的外来物种——我认为 Unisys 大型机是唯一的例外)。尽管如此,即使在 更常见的机器:

short a = 1;
std::cout << sizeof( a ) << std::endl;
std::cout << sizeof( a + 0 ) << std::endl;

应该给出不同的结果:第一个相当于 sizeof( short ),第二个sizeof( int )(因为 积分提升)。

这两个问题在形式上是正交的;右值和左值 与积分促销无关。 除了... 积分提升仅适用于右值,并且大多数(但不是 所有)您将使用右值的情况将导致 整体推广。因为这个原因,真的没有理由 返回小于int 的数值。 甚至有一个很好的理由不退货 一种字符类型。重载的运算符,如&lt;&lt;,经常表现 字符类型不同,所以你只想返回 字符作为字符类型。 (你可以比较 区别:

char f() { return 'a'; }
std::cout << f() << std::endl;      //  displays "a"
std::cout << f() + 0 << std::endl;  //  displays "97" on my machine

不同的是,在第二种情况下,加法有 导致发生积分提升,从而导致不同的 &lt;&lt; 的重载将被选择。

【讨论】:

  • 如果您能在回答中对return values are rvalues, subject to integral promotion 进行更多解释,那就太好了。
  • “返回值是右值……所以返回更小的值没有意义” 喜欢它
  • @AlvinWong:有关更多背景信息,请参阅Why are C character literals ints instead of chars? 的答案。
  • 在您的编辑添加了极好的解释之后,我希望我能再次 +1。
  • 如果是signed char 会怎样?它的行为会与签名的char 相同,还是会是不同的类型?
【解决方案2】:

故意不返回 -1、0 或 1。

它允许(注意这不适用于字符串,但它同样适用于字符串)

int compare(int *a, int *b)
{
   return *a - *b;
}

这比:

int compare(int *a, int *b)
{
   if (*a == *b) return 0;
   if (*a > *b) return 1;
   return -1;
}

如果您必须返回 -1、0 或 1,这就是您必须做的 [或类似的事情]。

它也适用于更复杂的类型:

class Date
{
    int year;
    int month;
    int day;
}

int compare(const Date &a, const Date &b)
{
   if (a.year != b.year) return a.year - b.year;
   if (a.month != b.month) return a.month - b.month;
   return a.day - b.day;
}

在字符串的情况下,我们可以这样做:

int compare(const std::string& a, const std::string& b)
{
   int len = min(a.length(), b.length());

   for(int i = 0; i < len; i++)
   {
      if (a[i] != b[i]) return a[i] - b[i];
   }
   // We only get here if the string is equal all the way to one of them
   // ends. If the length isn't equal, "longest" wins. 
   return a.length() - b.length();
}

【讨论】:

  • 您的第一个compare 函数存在溢出问题,如果它采用char*char 小于int,则(幸运的是)不会同样适用。例如,如果*aMAX_INT 并且*b-1 那么*a - *b 是UB,但如果实现选择定义其行为,那么结果几乎肯定是否定的。
  • 最后一个例子的问题:length() 返回一个size_t,它可能大于int...
  • 是的,如果您的字符串长度超过 2GB,这可能是个问题。我已经完成了 1GB 长字符串作为测试用例,用于将内容存储在 fifo 中一次。但可以肯定的是,处理包含编码为 Base64 的 MPEG 的字符串的人可能会遇到这个问题......
  • @MatsPetersson 这更像是一个基本问题,因为问题是“为什么它返回一个 int?”
  • 好吧,我敢肯定那是歇斯底里的——我的意思是历史原因——可能是因为它与 strcmp/memcmp 和其他比较类型的操作兼容。
【解决方案3】:

int 通常是(在大多数现代硬件上的意思)一个与系统总线和/或 cpu 寄存器大小相同的整数,即所谓的机器字。因此 int 通常比较小的类型传递得更快,因为它不需要对齐、屏蔽和其他操作。

存在较小的类型主要是为了优化数组和结构的 RAM 使用。在大多数情况下,它们会用几个 CPU 周期(以对齐操作的形式)换取更好的 RAM 使用率。

除非你需要强制你的返回值是一个百分号大小的有符号或无符号数(char、short…)你最好使用 int,这就是标准库这样做的原因。

【讨论】:

  • 以一种有意义的方式解释事物的硬件方面的好方法。
【解决方案4】:

假设有些人正在将代码从 C 更改为 C++。他们决定将strcmp 替换为string::compare

由于strcmp返回int,所以string::compare返回int作为礼物更容易。

【讨论】:

    【解决方案5】:

    因为一个布尔返回值只能是两个可能的值(真、假),而比较函数可以返回三个可能的值(小于、等于、大于)。

    更新

    虽然当然可以返回一个有符号的short,但如果你真的想要实现你自己的比较函数,你可以返回一个带有两个布尔值的半字节或结构值。

    【讨论】:

    • 问题中没有任何地方说明返回布尔类型。事实上,他特意提出shortchar作为int的替代品。
    【解决方案6】:

    可能使它更像strcmp,它也有这个set of return values。如果您想移植代码,那么让替换尽可能接近可能会更直观。

    此外,返回值不仅仅是-101,而是&lt;00&gt;0

    此外,正如前面提到的,由于退货受integral promotion 的约束,因此将其缩小是没有意义的。

    【讨论】:

      【解决方案7】:

      该方法实际上并没有返回集合{ -1, 0, 1 } 中的整数;它实际上可以是任何个整数值。

      为什么?我能想到的主要原因是int 应该是架构的“自然大小”值;对这种大小的值的操作通常至少与对较小或较大值的操作一样快(并且在许多情况下更快)。所以这是一个允许实现足够松弛以使用最快的情况的情况。

      【讨论】:

        【解决方案8】:

        这是一种 C 主义。

        当 C 需要 compare 类型的函数时,它们总是返回 int。 C++ 只是将其发扬光大(不幸的是)。

        然而,返回int 实际上可能是最快的方法,因为它通常是所用系统寄存器的大小。 (故意模糊。)

        【讨论】:

        • 实际上shortchar 可以施加性能惩罚,例如255+7charint 具有不同的值,因此正确的实现不一定简单地将 char 存储在 int 可以在不处理其语义的情况下。编译器不一定会优化由此带来的低效率。
        【解决方案9】:

        如果我要设计一个比较 Foo 类型的两个对象的 compare 方法,并且我只想返回 -1、0 或 1,那么使用 short 或 char 通常是个好主意吗?

        没问题。更好的方法是返回布尔值(如果只想比较是否相等)或枚举(获取更多信息):

        enum class MyResult
        {
          EQUAL,
          LESS,
          GREATER
        };
        
        MyResult AreEqual( const Foo &foo1, const Foo & foo2 )
        {
          // calculate and return result
        }
        

        【讨论】:

        • “没问题”。你有这样做的理由吗?
        猜你喜欢
        • 2019-10-12
        • 2017-06-12
        • 2020-10-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-19
        • 1970-01-01
        • 2013-09-23
        相关资源
        最近更新 更多