I am reading again "C++ Primer, 5th edition". In chapter 16 about templates, there is an example of "template Non-type parameters":
template<unsigned N, unsigned M>
int compare(const char (&p1)[N], const char (&p2)[M])
{
return strcmp(p1, p2);
}
int main()
{
cout << compare("hi", "mom") << endl;
cout << strcmp("hi", "mom") << endl;
std::cout << "\ndone!\n";
}
As we know, strcmp()
compares two character strings and returns 0
for equality, a positive value if str1
is greater than str2
, and a negative value if str1
is less than str2
, and this is what I get inside main()
calling strcmp()
.
The problem is in the book example that calls strcmp()
inside the template function, so when I run the program I get:
output:
-5
-1
What is the problem in the code? And why are the two giving different values for the same arguments?
The return value from strcmp is 0 if the two strings are equal, less than 0 if str1 compares less than str2 , and greater than 0 if str1 compares greater than str2 .
While comparing the two function, in a loop repeted 500'000'000 times, strcmp execute too much fast, about x750 times faster. The execution time of that function is 3.058s , while strcmp only 0.004s .
The strcmp() built-in function compares the string pointed to by string1 to the string pointed to by string2 The string arguments to the function must contain a NULL character ( \0 ) marking the end of the string.
This is a compiler optimization applied when strcmp
is passed literal parameters, even on -O0. See this compiler explorer link: https://godbolt.org/z/T4EKxr
#include <cstring>
template<unsigned N, unsigned M>
int compare(const char (&p1)[N], const char (&p2)[M])
{
return strcmp(p1, p2);
}
int a() {
return compare("hi", "mom");
}
int b() {
return strcmp("hi", "mom");
}
The generated assembly:
.LC0:
.string "mom"
.LC1:
.string "hi"
a():
push rbp
mov rbp, rsp
mov esi, OFFSET FLAT:.LC0
mov edi, OFFSET FLAT:.LC1
call int compare<3u, 4u>(char const (&) [3u], char const (&) [4u])
pop rbp
ret
b():
push rbp
mov rbp, rsp
mov eax, -1
pop rbp
ret
int compare<3u, 4u>(char const (&) [3u], char const (&) [4u]):
push rbp
mov rbp, rsp
sub rsp, 16
mov QWORD PTR [rbp-8], rdi
mov QWORD PTR [rbp-16], rsi
mov rdx, QWORD PTR [rbp-16]
mov rax, QWORD PTR [rbp-8]
mov rsi, rdx
mov rdi, rax
call strcmp
leave
ret
As we can see, for b()
above, gcc is optimizing the call to strcmp
to just a -1
, whereas it actually calls strcmp
for a()
. This is valid behavior, as strcmp
returns:
Negative value if lhs appears before rhs in lexicographical order.
Zero if lhs and rhs compare equal.
Positive value if lhs appears after rhs in lexicographical order.
-1
is negative.
If we turn on optimizations, gcc will similarly optimize a()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With