Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ string literal equality check?

== is not how we compare two arrays, since that would only compare the addresses:

#include <iostream>

int main()
{
  char a[] = "aaa";
  char b[] = "aaa";

  if (a == b)
    std::cout << "Yes" << std::endl;
  else
    std::cout << "No" << std::endl;

  return 0;
}

This code even gives me a warning:

Array comparison always evaluates to false

But when I tried this:

if ("aaa" == "aaa")

It seemed to be working fine. Still gives me a warning, but the warning is:

Condition is always true

At first, I thought it was some kind of caching thing, so I tried a rather unusual string literal:

if ("whuiwhqohqweihqweohi" == "whuiwhqohqweihqweohi")

Still works fine both on MSVC and g++. Is that an implementation dependent behavior? I understand that comparing variables which are known at compile-time is not very useful, but my question is just "how come this is the case?".

Additionally, using auto seems to be also working:

#include <iostream>

int main()
{
  auto a = "whuiwhqohqweihqweohi";
  auto b = "whuiwhqohqweihqweohi";
  if (a == b) {
    std::cout << "Yes" << std::endl;
  }
  else {
    std::cout << "No" << std::endl;
  }

  return 0;
}

This code produces the correct output. What is the type of a and b here?

Please do not answer "Use std::string". It's irrelevant to my question

like image 514
Ayxan Haqverdili Avatar asked Dec 04 '22 19:12

Ayxan Haqverdili


1 Answers

You have to be very careful here, as some of the cases you're looking at aren't quite equivalent to others.

In your first example:

char a[] = "aaa";
char b[] = "aaa";

if (a == b)

You're creating two arrays of char, each initialized from an string literal. You're then attempting to compare those arrays to each other. In most cases (including this one) the name of an array evaluates to the address of the first element in that array. So you're really comparing the addresses of the two arrays. Those can't be the same, so the comparison is guaranteed to yield false.

In your second example: if ("aaa" == "aaa"), you're comparing the string literals themselves, rather than arrays initialized from the string literals.

The result of this is not guaranteed by the standard. The standard allows (but does not require) that identical string literals be merged together. Again, however, what you're really comparing isn't the contents of the literals--it's the addresses at which they're stored. If the compiler merges the string literals so they're at the same address, this will yield true. If it keeps them separate, it'll yield false.

In your auto case:

auto a = "whuiwhqohqweihqweohi";
auto b = "whuiwhqohqweihqweohi";

You have pretty much the same situation--a and b both end up as pointers to char, holding the addresses of the string literals. If the compiler merges those literals, they'll both point to the same address so they'll compare equal. If the compiler doesn't merge them together, each will have its own address, and they'll compare as not equal.

The big point here is that none of these is comparing the contents of the strings at all, only the addresses at which they're stored. The content counts only to the degree that two string literals can only be merged if they have (or at least end with) the same content.

As far as "at least end with" goes, I'm referring to the fact that a compiler if you had something like: "wing" in one place and "swing" in another, the compiler is free to merge the two, so with code something like:

auto a = "wing";
auto b = "swing";

...the compiler could store swing in one place, and initialize a to point to the second character of that stored literal.

like image 200
Jerry Coffin Avatar answered Dec 20 '22 17:12

Jerry Coffin