0

I was trying the function max() using visual-studio 2022 Version 17.7.1

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
    cout << max("5", "4") << "\n";
    return 0;
}

and the Output is :

4

and when I change the code to :

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
    cout << max("4","5") << "\n";
    return 0;
}

the Output is :

5

but when I am using codeblocks :

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
    cout << max("5", "4") << "\n";
    return 0;
}

and the Output is :

5

and when I change the code to :

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
    cout << max("4","5") << "\n";
    return 0;
}

the Output is :

4

So visual-studio 2022 Version 17.7.1 choose the second parameter every time and codeblocks choose the first parameter every time ( I guess that ) but Why ? is that because the parameters is converted to const char* so the comparison every time ( in both visual-studio 2022 Version 17.7.1 and codeblocks ) is between two pointers so it is between two addresses ?

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
f877576
  • 447
  • 2
  • 7
  • You can’t compare strings like that – Daniel A. White Aug 28 '23 at 21:53
  • You are comparing pointers to string literals, not the actual integer values represented in those strings. It is undefined behavior to compare pointers for two disparate objects. Use `std::stoi` or `std::strtol` if you want to parse a string as an integer. – paddy Aug 28 '23 at 21:53
  • 2
    Related: [When are two pointers comparable?](https://stackoverflow.com/q/22471909/11082165), [Is it unspecified behavior to compare pointers to different arrays for equality?](https://stackoverflow.com/q/4909766/11082165) – Brian61354270 Aug 28 '23 at 21:54
  • Try explicitly writing `("4" < "5")` instead and see the warnings your compiler gives you. See also [Why should I always enable compiler warnings?](https://stackoverflow.com/q/57842756/11082165) – Brian61354270 Aug 28 '23 at 21:56
  • 1
    @Yksisarvinen that's not UB. The result is arbitrary but it isn't UB. – ALX23z Aug 28 '23 at 22:16
  • 1
    @ALX23z Hmm. I thought comparing pointers not from the same array is always UB. I stand corrected. – Yksisarvinen Aug 28 '23 at 22:21
  • Try `cout << max("5"s, "4"s) << "\n";` for better results — to compare **strings** rather than **pointers**. You'll need `using namespace std::literals::string_literals;`. – Eljay Aug 28 '23 at 23:09
  • in this code : `cout << max("5"s, "4"s) << "\n";` `"4"` and `"5"` are converted to `string` because of the `s operator` so this code : `cout << max("5"s, "4"s) << "\n";` is equivalent to this code : `string j="5"; string k="4"; cout << max(j,k) << "\n";` , right ? @Eljay – f877576 Aug 28 '23 at 23:26
  • That is correct. And `std::string` objects have intuitive behavior, whereas C-style C-string literal char arrays do not have beginner programmer friendly behavior (and I don't think their behavior is very friendly for seasoned programmers either). – Eljay Aug 28 '23 at 23:43

1 Answers1

6

In your calls of std::max there are compared addresses of string literals. The result of such a comparison in C++ is unspecified (in C it is undefined behavior).

From the C++20 Standard (7.6.9 Relational operators)

  1. ...The lvalue-to-rvalue (7.3.2), array-to-pointer (7.3.3), and function-to-pointer (7.3.4) standard conversions are performed on the operands. The comparison is deprecated if both operands were of array type prior to these conversions (D.5).

4 The result of comparing unequal pointers to objects81 is defined in terms of a partial order consistent with the following rules:

(4.1) — If two pointers point to different elements of the same array, or to subobjects thereof, the pointer to the element with the higher subscript is required to compare greater.

(4.2) — If two pointers point to different non-static data members of the same object, or to subobjects of such members, recursively, the pointer to the later declared member is required to compare greater provided the two members have the same access control (11.9), neither member is a subobject of zero size, and their class is not a union.

(4.3) — Otherwise, neither pointer is required to compare greater than the other

Instead you should write

#include <cstring>

//...

std::cout << std::max( "5", "4", []( const auto &s1, const auto &s2 ) { return std::strcmp( s1, s2 ) < 0; } ) << "\n";
std::cout << std::max( "4", "5", []( const auto &s1, const auto &s2 ) { return std::strcmp( s1, s2 ) < 0; } ) << "\n";

in this case the output will be

5
5

That is to compare two strings you need to use standard string function strcmp declared in header <cstring>.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • ٍSo My Code ( in My question ) in C++ is unspecified (in C it is undefined behavior) because the parameters ( `"5"` and `"4"` ) is converted to `const char*` so the comparison every time ( in both visual-studio 2022 Version 17.7.1 and codeblocks ) is between two pointers so it is between two addresses , right ? – f877576 Aug 28 '23 at 22:04
  • @f877576 You are right. Relational operators are not defined for arrays. Thus arrays in such operations are converted to pointers to their first elements. – Vlad from Moscow Aug 28 '23 at 22:05
  • Another possibility: Go straight to `std::string` where the comparison is what you would expect. But before you go and use this alternative, look at this: [Vlad's solution](https://godbolt.org/z/3fecrjYYh) the compiler can optimize down to constants and then out. The [`string` solution](https://godbolt.org/z/cnrjsEcEs)... No such luck. Compilers am smart, but not this smart. Yet. – user4581301 Aug 28 '23 at 22:40
  • 1
    @user4581301: `std::string_view` is better alternative than `std::string` and optimize well [Demo](https://godbolt.org/z/sTYYM1Y97). – Jarod42 Aug 28 '23 at 23:34
  • @Jarod42 Huh. Missed the memo about `stringview` literals. Yes, that's the best of both worlds. – user4581301 Aug 28 '23 at 23:37