24

I would like to create a macro which can compare 2 strings, and emit a compile time error if the condition isn't met. This could be though of as a compile time assertion.

I'm not sure how I could do this.

For instance:

STATIC_COMPARE("THIS STRING","THIS STRING") -> would emit a compile time error
STATIC_COMPARE("THIS STRING","THIS OTHER STRING) -> wouldn't emit a compile time error.

The macro would look something like

#define STATIC_COMPARE(str1,str2) if (str1==str2) emit an error with a message

So I guess the question boils down to being able to compare the 2 strings at compile time.

Avba
  • 14,822
  • 20
  • 92
  • 192
  • Are you assuming string literal pooling also Related to [Computing length of a C string at compile time. Is this really a constexpr?](http://stackoverflow.com/q/25890784/1708801) – Shafik Yaghmour Dec 15 '14 at 18:46

5 Answers5

25

Starting with C++17 std::string_view is available. It supports constexpr comparisson:

#include <string_view>

constexpr bool strings_equal(char const * a, char const * b) {
    return std::string_view(a)==b;
}

int main() {
    static_assert(strings_equal("abc", "abc" ), "strings are equal");
    static_assert(!strings_equal("abc", "abcd"), "strings are not equal");
    return 0;
}

Demo

Jan Herrmann
  • 2,717
  • 17
  • 21
18

You can do this with C++11 by using a constexpr function:

constexpr bool strings_equal(char const * a, char const * b) {
    return *a == *b && (*a == '\0' || strings_equal(a + 1, b + 1));
}

(See a demo)

It's not possible to do this prior to C++11, with the caveat that many compilers will compile equal string literals to be a pointer to the same location. On these compilers it's sufficient to compare the strings directly since they will both be evaluated as equal pointers.

cdhowie
  • 158,093
  • 24
  • 286
  • 300
  • that was using coliru on the same website. tried it on clang with 1y, works fine. will delete my comment. – Richard Hodges Dec 15 '14 at 18:54
  • I am trying to get this to work in Xcode - wasn't able to . Maybe there is another way to make a static assert in that environment. I found a few resources but wasn't able to get it to work. http://en.cppreference.com/w/cpp/language/static_assert – Avba Dec 16 '14 at 10:49
  • "the caveat that many compilers will compile equal string literals to be a pointer to the same location." String literals do not have memory locations. – Nils Jul 17 '19 at 08:46
  • 1
    @Nils A string literal creates an unnamed array with static storage duration. This array has a memory location, which is what the literal effectively refers to. So yes, a literal causes a memory location to exist, which can be compared as with any other pointer. – cdhowie Jul 17 '19 at 13:42
10

You can use constexpr functions. Here's the C++14 way:

constexpr bool equal( char const* lhs, char const* rhs )
{
    while (*lhs || *rhs)
        if (*lhs++ != *rhs++)
            return false;
    return true;
}

Demo.

Columbo
  • 60,038
  • 8
  • 155
  • 203
3

This can be done in C++ 11 using constexpr. By defining a recursive function you can check that the string are equal or not.

constexpr bool isequal(char const *one, char const *two) 
{
    return (*one && *two) ? (*one == *two && isequal(one + 1, two + 1)) : (!*one && !*two);
}

static_assert(isequal("foo", "foo"), "this should never fail");
static_assert(!isequal("foo", "bar"), "this should never fail");

This code I used thanks to Johannes Schaub and you can see the full SO post here

Community
  • 1
  • 1
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
0

The question asks for a way to generate a compile time warning on comparing two strings.

If you need this to work in C99 however, you can make an assertion error that will raise when the program tries to run, but was evaluated at compiler time.

#include <assert.h>
#include <string.h>

int main() {
    assert(strcmp("Thing1", "Thing2") != 0);
    return 0;
}

Modern versions of GCC and Clang will evaluate the string comparison at compile time, and the results can be seen when the code is run.

Tested this works as far back as GCC 4.1.2 (2007) and Clang 3.0.0 (2011).

You can see the comparison is done at compile time by using objdump to see the results:

$ gcc -Os -std=c99 static_strcmp_test.c -o static_strcmp_test
$ objdump --disassemble=main static_strcmp_test
...
0000000000001040 <main>:
    1040:       f3 0f 1e fa             endbr64 
    1044:       31 c0                   xor    %eax,%eax
    1046:       c3                      ret    

You can also try it online here: https://godbolt.org/z/Kb4GhT99Y

The Matt
  • 1,423
  • 1
  • 12
  • 22