为什么string :: compare返回一个int?


102

为什么string::compare返回一个int而不是较小的类型,例如shortor char?我的理解是,此方法仅返回-1、0或1。

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

编辑:我已经得到纠正,string::compare不返回-1、0或1,它实际上返回的值> 0,<0或0。感谢您一直陪伴我。

似乎答案很粗略,没有理由返回小于类型的类型,int因为返回值是“ rvalues”,而这些“ rvalues”不会因为小于int类型(4个字节)而受益。此外,许多人指出,int无论如何,大多数系统的寄存器可能都将具有一定的大小,因为无论您为它们提供1、2还是4字节的值,这些寄存器都将被填充,因此返回a并没有真正的优势。较小的值。

编辑2:实际上,当使用较小的数据类型(例如对齐,遮罩等)时,看起来可能会有额外的处理开销。通常的共识是,较小的数据类型在处理大量数据时会保留在内存中,例如数组的大小写。

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


我认为最好是使用一种更具体的类型。一种仅包含-1、0和1的Ada95样式。
Sachin Kainth

23
对于文档string::compare()链接到明确规定返回值<0,0,> 0 -not- -1,0和1
船长Obvlious

6
使用shortchar代替的好处是int什么?大多数架构都会将函数的返回值存储在寄存器中,而inta和a short或都将适合寄存器charchar对于数字类型使用总是一个坏主意,尤其是当您需要确保正确处理带符号的值时。
科迪·格雷

7
Obvlious上尉,您的名字和评论……简直是无价之宝。
科迪·史密斯

2
使用char将是一个坏主意,因为代码检查返回值是否小于零将在char未签名的平台上失败。
milleniumbug

Answers:


113

首先,规范是它将返回小于,等于或大于0,不一定是-1或的值1。其次,返回值是右值,需要进行整数提升,因此返回较小的值是没有意义的。

在C ++中(与在C中一样),每个表达式都是右值或左值。从历史上看,这些术语是指左值出现在分配的左侧,而右值只能出现在右侧的事实。如今,对于非类类型的一个简单近似是,左值在内存中有一个地址,而右值没有在内存中。因此,您不能使用右值的地址,并且cv限定词(其条件为“访问”)不适用。用C ++术语来说,没有类类型的右值是纯值,而不是对象。函数的返回值是一个右值,除非它具有引用类型。(例如,适合寄存器的非类类型几乎总是在寄存器中而不是在内存中返回。)

对于类类型,由于您可以在右值上调用成员函数,因此问题更为复杂。这意味着右值实际上必须具有用于this 指针的地址,并且可以cv限定,因为cv限定在重载解析中起作用。最后,C ++ 11引入了几个新的区别,以支持右值引用。这些也主要适用于类类型。

积分提升是指以下事实:当小于an的整数类型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。甚至有很好的理由不将其返回为字符类型。像的重载运算符<<在字符类型上的行为通常会有所不同,因此您只想将字符作为字符类型返回。(您可以比较差异:

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

不同之处在于,在第二种情况下,加法引起积分提升,导致<<选择了不同的过载。


46
如果您可以return values are rvalues, subject to integral promotion在答案中进一步解释,那就太好了。
Alvin Wong

“返回值是右值...因此,返回任何较小的值都是没有意义的”, 就像
masoud 2013年

1
@AlvinWong:请参阅“ 为什么C字符文字是整数而不是char?”的答案有关更多背景信息。
杰西·古德

希望在您的编辑添加了精妙的解释后,我可以再次为此+1。
科迪·格雷

如果是signed char呢?它的行为是否与signed相同char,或者是不同的类型?
2013年

41

故意不返回-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();
}

8
您的第一个compare函数存在溢出问题,(如果有问题)char*char小于,就无法平等地应用它int。例如,如果*aMAX_INT*b-1然后*a - *b是UB,但如果实现选择几乎肯定定义其行为则结果为阴性。
史蒂夫·杰索普

1
您的最后一个示例的问题:length()返回的a size_t可能大于int
F'x 2013年

是的,如果您的字符串长度超过2GB,那可能是个问题。我已经做了一个1GB长的字符串作为测试用例,可以将它们一次存储在fifo中。但是可以肯定的是,有人处理包含编码为Base64的MPEG的字符串或类似字符串的人很可能会遇到这个问题……
Mats Petersson

@MatsPetersson基本上是一个基本问题,因为问题是“为什么它返回一个int?”
F'x

好吧,我确定这是歇斯底里的-我的意思是历史原因-可能与strcmp / memcmp和其他比较类型操作兼容。
Mats Petersson

25

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

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

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


用有意义的方式解释事物的硬件方面的好方法。
Ogre Psalm33,2013年

10

这是一种C主义。

当C是必需compare类型的函数时,它们始终返回int。C ++只是将它向前推进了(不幸的是)。

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


1
其实 short并且char可能会施加性能损失,例如,255+7对于a char和a具有不同的值,int因此正确的实现不一定会简单地将a can 存放在char哪里int而无需照顾其语义。编译器不一定会优化这种做法带来的效率低下。
杰克·艾德利2013年

10

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

为什么?我能想到的主要原因int是应该是该体系结构的“自然大小”值。通常,对这种大小的值进行操作至少比对较小或较大的值进行操作(在许多情况下更快)。因此,这是一种允许实现足够松弛以使用最快的方法的情况。


4

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

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

enum class MyResult
{
  EQUAL,
  LESS,
  GREATER
};

MyResult AreEqual( const Foo &foo1, const Foo & foo2 )
{
  // calculate and return result
}

3
“那没关系”。您有理由吗?
jrok 2013年

4

假设有人将代码从C更改为C ++。他们决定更换strcmpstring::compare

自从return 以来,strcmpint它作为礼物string::compare返回就更容易int了。



-1

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

更新资料

虽然肯定可以返回带符号的short,但是如果您确实想实现自己的compare函数,则可以返回带有两个布尔值的半字节或结构值。


7
这个问题在任何地方都没有说关于返回布尔类型的任何事情。事实上,他特别提出short,并char作为替代品int
科迪·格雷
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.