2

I came across this question on SO, and this answer to the question. The code is as follows:

int main()
{

    char u[10];
    cout<<"Enter shape name ";
    cin>>u;
    if(u=="tri") //IS THIS UNDEFINED BEHAVIOR because the two decayed pointers both point to unrelated objects?
    {
        cout<<"everything is fine";
    }
    else
    {
        cout<<"Not fine";
    }
    return 0;
}

I have read in the mentioned answer that, both u and "tri" decay to pointers to their first element. My question is that, now is comparing these two decayed pointers undefined behavior because these pointers point to unrelated objects? Or the program is fine/valid(no UB) and because the pointers have different values, the else branch will be executed?

cigien
  • 57,834
  • 11
  • 73
  • 112
Jason
  • 36,170
  • 5
  • 26
  • 60

4 Answers4

5

Comparing pointers via == is defined in compound#expr:

If at least one of the operands is a pointer, pointer conversions, function pointer conversions, and qualification conversions are performed on both operands to bring them to their composite pointer type. Comparing pointers is defined as follows:

(3.1) If one pointer represents the address of a complete object, and another pointer represents the address one past the last element of a different complete object, the result of the comparison is unspecified.

(3.2) Otherwise, if the pointers are both null, both point to the same function, or both represent the same address, they compare equal.

(3.3) Otherwise, the pointers compare unequal.

Neither of the pointers in your example represents the address one past the last element of a [different] complete object. Neither pointer is null. They do not represent the same address. Hence u=="tri" is false.

Comparing pointers via < is a different story, because there needs to be some ordering among the pointer values. To compare two pointers via == it only matters whether their value is the same or not.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
5

Standard says:

[expr.eq]

The == (equal to) and the != (not equal to) operators group left-to-right. The lvalue-to-rvalue ([conv.lval]), array-to-pointer ([conv.array]), and function-to-pointer ([conv.func]) standard conversions are performed on the operands...

Hence, we are comparing pointers to the respective arrays.

If at least one of the operands is a pointer, ... Comparing pointers is defined as follows:

  • If one pointer represents the address of a complete object, and another pointer represents the address one past the last element of a different complete object,72 the result of the comparison is unspecified. [does not apply since neither pointer is past last element]
  • Otherwise, if the pointers are both null, both point to the same function, or both represent the same address, they compare equal. [does not apply since neither is null, neither point to functions, nor represent same address]
  • Otherwise, the pointers compare unequal. [applies]

The behaviour is defined and else branch will be unconditionally executed.

Unconditionally unconditional if-statements imply that there is probably a bug; most likely the author was trying to compare the content of the arrays, which the operator does not do.


"warning: comparison with string literal results in unspecified behavior"

I believe that this warning message is slightly misleading. Comparison with two string literals would be unspecified:

if ("tri" == "tri")

It's unspecified whether this conditional is true or false.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • 1
    @Mike `if (false) else ...` is unconditionally executing the else branch. The `if` is superfluous, its a bug or a typo – 463035818_is_not_an_ai Mar 01 '22 at 09:04
  • @Mike It means that there is no state of the program where the other branch would ever be taken. The compiler can take advantage of this and for example optimise by removing the conditional check and the code in the branch that will never be chosen. – eerorika Mar 01 '22 at 09:05
  • 1
    @Mike `But does this necessarily imply that the if condition will never be tested?` No, it does not mean that. It's an optimisation; not something guaranteed by the standard. – eerorika Mar 01 '22 at 09:11
  • 1
    @Mike according to the standard it does not matter if the condition is checked or not, because it can never be `true`. You cannot tell the difference between: A) At runtime the condition is checked and B) the condition is ignored and always the else branch is taken. And the compiler will notice that and optimize accordingly. See https://stackoverflow.com/questions/15718262/what-exactly-is-the-as-if-rule – 463035818_is_not_an_ai Mar 01 '22 at 09:16
  • Why does it matter if the string literals are defined in different translation units? – Jakob Stark Mar 01 '22 at 09:33
  • @JakobStark I checked the rule and it indeed doesn't matter for the standard. There's an implementation detail though that most(/all?) compilers store string literal of one TU once and hence would optimise `if ("tri" == "tri")` into `if (true)`. – eerorika Mar 01 '22 at 09:42
  • @Mike It's a reference to a footnote. – eerorika Mar 01 '22 at 11:07
  • @Mike Because `u` is not a string literal and it's not unspecified whether that's the same object as string literal or not. It's not the same object. – eerorika Mar 01 '22 at 11:14
1

The code won't do what the author presumably wanted it to do, but there's no UB. While comparing pointers to unrelated objects with < has unspecified results, checking equality is fine, and the comparison will produce false.

Sneftel
  • 40,271
  • 12
  • 71
  • 104
-3

I don't think this is going to lead to undefined behavior but it definitely doesn't give correct results.

Using a debugger, look at the values you're comparing. For example if the input is "tri":

u == { 't','r','i','\0','\0','\0','\0','\0','\0','\0' }
"tri" == { 't','r','i','\0' }

..as you can see they're both different. Thus leading to their comparison resulting false.

You can prove this by setting the size of u to 4 (int u[4]) and then giving the input "tri". You'll get the output

everything is fine

But this is not a flexible fix because it won't work with inputs > or < than 3 (or 4 by counting the null termination character \0). To fix this issue, just convert your char array into a std::string:

#include<iostream>
#include<string>

int main()
{
    char u[10]{};
    std::cout << "Enter shape name ";
    std::cin >> u;

    if (std::string(u) == "tri") // Works fine now
    {
        std::cout << "everything is fine";
    }
    else
    {
        std::cout << "Not fine";
    }
    return 0;
}

..or maybe just use std::string directly:

std::string u;
std::cout << "Enter shape name ";
std::cin >> u;

if (u == "tri")
{
// ...
The Coding Fox
  • 1,488
  • 1
  • 4
  • 18
  • `..as you can see they're both different. Thus leading to their comparison resulting false.` The content of the array has nothing to do with the result of the comparison. You would **not** get "everything is fine" if you used array of size 4. – eerorika Mar 01 '22 at 09:20
  • In my case it made a difference. So I mentioned it in the answer. – The Coding Fox Mar 01 '22 at 09:22
  • The argument "in my case it made a difference" is a bad one if the question is about undefined behaviour. If it is indeed UB, it may or may not make a difference depending on the compiler and system you are using. Just 'trying' somehing out does not answer questions about UB. – Jakob Stark Mar 01 '22 at 10:08
  • "_You can prove this by setting the size of u to 4 (int u[4]) and then giving the input "tri". You'll get the output everything is fine_": If that happens then your compiler is broken. With `int u[4]` and input `tri` the program still has well-defined behavior executing the `else` branch. Also, please note that the question is tagged `language-lawyer`, so the purpose of the question is not to find a work-around/solution for the problem, but to determine whether the program has well-defined behavior or not according to the standard. – user17732522 Mar 01 '22 at 10:34
  • I am using MSVC compiler. And it works for me. – The Coding Fox Mar 01 '22 at 10:36