1

I read many time the == operator doesn't works on C strings. But I'm confused by this sample, tested thanks to Coliru website.

#include <stdio.h>

typedef struct S {
    const char *data;
} S;

const char *Text = "hello";

void test()
{
    n = { "hello" };
    printf("%d\n", n.data == Text);
}

int main(void) 
{
    test();
    return 0;
}

If you change any letter of a value, (Text or n), the result is 0 and if it is exactly the same the result is 1.

If == is unsuitable for strings, in which case this operator will give unexpected results ?

chqrlie
  • 131,814
  • 10
  • 121
  • 189
Ploumploum
  • 311
  • 1
  • 9
  • Unsuitable doesn't mean 100% inaccurate. But if you're relying on something for value equality, would you want the tool that's accurate 30% of the time, or 100% of the time? In the end `==` serves a purpose different than what you're using it for – Rogue Feb 09 '21 at 19:14
  • 7
    The compiler is apparently using [string interning](https://en.wikipedia.org/wiki/String_interning). That behavior is compiler dependent, and should not be relied on. – Warren Weckesser Feb 09 '21 at 19:14
  • 2
    There is no guarantee by the C standard that separate string literals of identical content will always occupy the same memory. Do not rely on this. – Oka Feb 09 '21 at 19:15
  • 2
    You're comparing the _addresses_ of what the two _pointer_ variables point to and _not_ the actual content. This works _iff_ the compiler/linker coalesces the two _distinct_ string literals into one. If you had an `extern` (e.g. `extern const char *Text2;`) and defined it in a different `.c/.o` file (e.g.) `const char *Text2 = "hello";`, this would [probably] fail to match. If the extern was defined as: `const char Text2[] = "hello";` it would almost certainly fail to match. Again, you're comparing _addresses_, but you need to compare _contents_, so you should [always] use `strcmp` or equiv. – Craig Estey Feb 09 '21 at 19:32

2 Answers2

2

The == operator, as well as the relations comparison operators <, <=, > and >=, when applied to pointer types, compares the pointer values, not the objects pointed to.

Hence a == b will evaluate to 1 if and only if a and b point to the same object.

In your example, Text and n.data are initialized with two identical string literals "hello". It is implementation defined whether these string literals are compiled as 2 different objects or as a single object.

On your system, the compiler generates the same object, so both pointers point to the same object and thus are identical.

Try this code to verify that == is inappropriate to compare strings:

#include <stdio.h>
#include <string.h>

typedef struct S {
    const char *data;
} S;

int main(void) {
    char copy[] = "hello";
    const char *Text = "hello";
    S n = { "hello" };

    printf("pointer comparison: %d, string comparison: %d\n",
           n.data == Text, strcmp(n.data, Text) == 0);

    printf("pointer comparison: %d, string comparison: %d\n",
           n.data == copy, strcmp(n.data, copy) == 0);

    return 0;
}

Output:

pointer comparison: 1, string comparison: 1
pointer comparison: 0, string comparison: 1
chqrlie
  • 131,814
  • 10
  • 121
  • 189
1

The result of this call

printf("%d\n", n.data == Text);

is implementation defined. This call can output either 1 or 0. There are compared two pointers (their values) to identical string literals (to first characters of identical literals). The result depends on compiler options that is whether the compiler stores identical string literals as distinct arrays or as one array (with static storage duration).

From the C Standard (6.4.5 String literals)

7 It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.

To compare strings you should use the standard C string function strcmp.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335