Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

memcmp versus strcmp, why is memcmp faster?

Status
Not open for further replies.

SkiLift

Programmer
Dec 18, 2003
47
0
0
US
Why is memcmp faster than strcmp?
 
Maybe because it isn't checking to see if it hits a NULL? I don't see anything else that it would be doing differently.
 
Have you checked that it's faster or you read it somewhere?

Cheers,
Dian
 
Compare real memcmp/strcmp core loops:
Code:
/* MS VC++ RTL memcmp core loops: */
while ( --count && *(char *)buf1 == *(char *)buf2 ) {
  buf1 = (char *)buf1 + 1;
  buf2 = (char *)buf2 + 1;
  }
...
/* MS VC++ RTL strcmp core loop: */
while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
     ++src, ++dst;
...
The strcmp has one extra compare (and memory access) op...
 
During a code review, I was told to change my strcmp to a memcmp, because strcmp is too expensive. I'm pretty sure he is correct, but I was wondering why. The loop gets moderate use. Here is the old code:
Code:
if (!(lWordIndex == 0 &&			
      strcmp(str1, "Z") == 0 ||
      strcmp(str1, "X") == 0 ) &&
      lPhoneticName == &lWord[lWordIndex][0]))
{
I cant use a char compare, like str1[0] == 'Z', because I dont know how long str1 is. Here is the new if. Notice I moved the fourth condition to the second which is a great time saving idea, but I'm not sure how much the memcmp pays off because I had to add a strlen operation.
Code:
if (!(lWordIndex == 0 &&
      lPhoneticName == &lWord[lWordIndex][0] &&
      strlen(str1) == 1  &&
      (memcmp(str1, "Z", 1) == 0 ||
       memcmp(str1, "X", 1) == 0    )))
{
 
Ooops...missing a open paren before the first strcmp in the first code block.
 
No need for strlen():
Code:
if (!(lWordIndex == 0 &&
      lPhoneticName == &lWord[lWordIndex][0] &&
      (memcmp(str1, "Z", [COLOR=red]2[/color]) == 0 ||
       memcmp(str1, "X", [COLOR=red]2[/color]) == 0    )))
{
 
If you use strncmp instead of strmcp you get the same loop as memcmp. I don't think there will be noticeable differences.

Cheers,
Dian
 
memcmp(str1, "Z", 2) is a great idea to get rid of the strlen, but is harder to read or understand what's going on and why (for maintainability).

I like the strcmp because of the readability. I would use the memcmp if I did not have to add either the strlen or the memcmp(str1, "Z", 2) trick.

memcmp is good for comparing structures and the like.

It does not appear that there is significant time savings. That's my opinion.

Great input by everyone.
 
> During a code review, I was told to change my strcmp to a memcmp, because strcmp is too expensive.
How about looking at what the profiler is telling you is really expensive, rather than on someone's ideas as to what might be expensive.

Sacrificing readability for minor performance gains is rarely worthwhile IMO.

Besides, for such short strings, why not just save a function call and unroll it yourself into
[tt]str[0] == 'Z' && str[1] == '\0'[/tt]

> memcmp is good for comparing structures and the like.
No it isn't.
Whilst it seems like it should, you have to remember that structures can have padding, and that the padding is always(*) undefined. All well and good except that memcmp will try and compare one structs padding with another structs padding.

Unless you initialise each struct with a memset, then I don't think you can be sure of the state of any padding.

Further, using memcmp() to compare structs containing pointers is most definitely the wrong thing to be doing.


--
If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
 
You're right about unrolling it yourself!

My bad about memcmp and structs...I actually do know better than that :)
 
Unless it is a time critical piece of code, I wouldn't change it. If the code is only going to be executed once, say, on initialization, does it make a lot of difference whether the system starts up 2ms slower?

If, on the other hand, it is executed millions of times, then it is worth changing.
 
Assuming there's an actual gain. Did anyone run a test to measure that?

And even if there's one, I bet there are a lot of simpler changes that will give you a bigger performace gain.

Cheers,
Dian
 
It all has to do with memory alignment. strcmp does a byte compare if either of the arguments is not aligned to a word boundary. memcmp returns non-zero if either are unaligned; otherwise is does block compares (4 bytes at a time on a 32 bit architecture).
 
> memcmp returns non-zero if either are unaligned
Rubbish - the alignment of the two things being compared does not affect the result. It might affect the internal implementation, but that's a completely different issue.


--
If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
 
> memcmp() does block compares (4 bytes at a time on a 32 bit architecture)

I thought about this case at first time as well, but it is faster for big endians only. For little endians it is not so simple:

Code:
union
{
char chars[4];
int word;
} first, second;

first.word < second.word

does not mean

first.chars < second.chars
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top