Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does string::compare return an int?

Tags:

c++

Why does string::compare return an int instead of a smaller type like short or char? My understanding is that this method only returns -1, 0 or 1.

Second part, if I was to design a compare method that compares two objects of type Foo and I only wanted to return -1, 0 or 1, would using short or char generally be a good idea?

EDIT: I've been corrected, string::compare does not return -1, 0, or 1, it in fact returns a value >0, <0 or 0. Thanks for keeping me in line guys.

It seems like the answer is roughly, there is no reason to return a type smaller than int because return values are "rvalues" and those "rvalues" don't benefit from being smaller than type int (4 bytes). Also, many people pointed out that the registers of most systems are probably going to be of size int anyway, since these registers are going to be filled whether you give them a 1, 2 or 4 byte value, there is no real advantage to returning a smaller value.

EDIT 2: In fact it looks like there may be extra processing overhead when using smaller datatypes such as alignment, masking, etc. The general consensus is that the smaller datatypes exist to conserve on memory when working with a lot of data, as in the case of an array.

Learned something today, thanks again guys!

like image 814
Cody Smith Avatar asked Mar 11 '13 12:03

Cody Smith


People also ask

What happens when you compare strings in C++?

The compare() function in C++ The compare() function compares two strings and returns the following values according to the matching cases: Returns 0, if both the strings are the same. Returns <0, if the value of the character of the first string is smaller as compared to the second string input.

How does string compare work?

The algorithm to compare two strings is simple: Compare the first character of both strings. If the first character from the first string is greater (or less) than the other string's, then the first string is greater (or less) than the second. We're done.

How does string compare work in C#?

The C# Compare() method is used to compare first string with second string lexicographically. It returns an integer value. If both strings are equal, it returns 0. If first string is greater than second string, it returns 1 else it returns -1.


2 Answers

First, the specification is that it will return a value less than, equal to or greater than 0, not necessarily -1 or 1. Secondly, return values are rvalues, subject to integral promotion, so there's no point in returning anything smaller.

In C++ (as in C), every expression is either an rvalue or an lvalue. Historically, the terms refer to the fact that lvalues appear on the left of an assignment, where as rvalues can only appear on the right. Today, a simple approximation for non-class types is that an lvalue has an address in memory, an rvalue doesn't. Thus, you cannot take the address of an rvalue, and cv-qualifiers (which condition "access") don't apply. In C++ terms, an rvalue which doesn't have class type is a pure value, not an object. The return value of a function is an rvalue, unless it has reference type. (Non-class types which fit in a register will almost always be returned in a register, for example, rather than in memory.)

For class types, the issues are a bit more complex, due to the fact that you can call member functions on an rvalue. This means that rvalues must in fact have addresses, for the this pointer, and can be cv-qualified, since the cv-qualification plays a role in overload resolution. Finally, C++11 introduces several new distinctions, in order to support rvalue references; these, too, are mainly applicable to class types.

Integral promotion refers to the fact that when integral types smaller than an int are used as rvalues in an expression, in most contexts, they will be promoted to int. So even if I have a variable declared short a, b;, in the expression a + b, both a and b are promoted to int before the addition occurs. Similarly, if I write a < 0, the comparison is done on the value of a, converted to an int. In practice, there are very few cases where this makes a difference, at least on 2's complements machines where integer arithmetic wraps (i.e. all but a very few exotics, today—I think the Unisys mainframes are the only exceptions left). Still, even on the more common machines:

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

should give different results: the first is the equivalent of sizeof( short ), the second sizeof( int ) (because of integral promotion).

These two issues are formally orthogonal; rvalues and lvalues have nothing to do with integral promotion. Except... integral promotion only applies to rvalues, and most (but not all) of the cases where you would use an rvalue will result in integral promotion. For this reason, there is really no reason to return a numeric value in something smaller than int. There is even a very good reason not to return it as a character type. Overloaded operators, like <<, often behave differently for character types, so you only want to return characters as character types. (You might compare the difference:

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

The difference is that in the second case, the addition has caused integral promotion to occur, which results in a different overload of << to be chosen.

like image 193
James Kanze Avatar answered Sep 26 '22 03:09

James Kanze


It is intentional that it doesn't return -1, 0 or 1.

It allows (note this is not for strings, but it applies equally to strings)

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

which is a lot less cumbersome than:

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

which is what you'd have to do [or something along those lines] if you have to return -1, 0 or 1.

And it works for more complex types too:

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; } 

In the string case, we can do this:

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(); } 
like image 33
Mats Petersson Avatar answered Sep 23 '22 03:09

Mats Petersson