c - How to compare a string with a short string literal effectively -


if don't want overhead needed call strcmp, compare strings short string literals way described in following code example:

#ifdef little_endian        //little-endian-addressing #define bytesasdword_m(a, b, c, d)\   ((ulong) ((a) | ((b) << 8) | ((ulong) (c) << 16) | ((ulong) (d) << 24)))  #define bytesasword_m(a, b)((ushort) ((a) | ((b) << 8)))  #else //little_endian       //little-endian-addressing #define bytesasdword_m(a, b, c, d)\  ((ulong) ((d) | ((c) << 8) | ((b) << 16) | ((a) << 24)))  #define bytesasword_m(a, b) ((ushort) ((b) | ((a) << 8))) #endif //little_endian      //little-endian-addressing  bool abscompare(char* chr_p) //compare string  "abs" {   if (*((ulong*) &chr_p[1]) ==     bytesasdword_m('a', 'b', 's', '\0'))     return true;    return false; } 

gcc compiles example long compile without optimization options enabled. optimization enabled warning:

"dereferencing type-punned pointer break strict-aliasing rules"

even optimizing -o3 doesn't result in effective code example illustrates:

//abstest.c  #include <string.h>  typedef unsigned long ulong; typedef unsigned short ushort;  #if byte_order == little_endian     //little-endian-addressing #define bytesasdword_m(a, b, c, d)\   ((ulong) ((a) | ((b) << 8) | ((ulong) (c) << 16) | ((ulong) (d) << 24)))  #define bytesasword_m(a, b)((ushort) ((a) | ((b) << 8)))  #else //byte_order == little_endian //little-endian-addressing #define bytesasdword_m(a, b, c, d)\  ((ulong) ((d) | ((c) << 8) | ((b) << 16) | ((a) << 24)))  #define bytesasword_m(a, b) ((ushort) ((b) | ((a) << 8))) #endif //byte_order == little_endian    //little-endian-addressing  int abscompare1(char* chr_p) {   return *(ulong*) chr_p ==  bytesasdword_m('a', 'b', 's', '\0'); }  int abscompare2(char* chr_p) {   return strcmp(chr_p, "abs"); }  int main(int argc __attribute__((unused)), char ** argv) {   int i;   int j;    = abscompare1(argv[0]);   j = abscompare2(argv[0]);    return + j; } 

objdump -d -mintel abstest:

080483d0 <abscompare1>:  80483d0:   55                      push   ebp  80483d1:   89 e5                   mov    ebp,esp  80483d3:   8b 45 08                mov    eax,dword ptr [ebp+0x8]  80483d6:   5d                      pop    ebp  80483d7:   81 38 61 62 73 00       cmp    dword ptr [eax],0x736261  80483dd:   0f 94 c0                sete   al  80483e0:   0f b6 c0                movzx  eax,al  80483e3:   c3                      ret      080483f0 <abscompare2>:  80483f0:   55                      push   ebp  80483f1:   0f b6 0d 5c 85 04 08    movzx  ecx,byte ptr ds:0x804855c  80483f8:   89 e5                   mov    ebp,esp  80483fa:   8b 55 08                mov    edx,dword ptr [ebp+0x8]  80483fd:   0f b6 02                movzx  eax,byte ptr [edx]  8048400:   29 c8                   sub    eax,ecx  8048402:   75 2b                   jne    804842f <abscompare2+0x3f>  8048404:   0f b6 42 01             movzx  eax,byte ptr [edx+0x1]  8048408:   0f b6 0d 5d 85 04 08    movzx  ecx,byte ptr ds:0x804855d  804840f:   29 c8                   sub    eax,ecx  8048411:   75 1c                   jne    804842f <abscompare2+0x3f>  8048413:   0f b6 42 02             movzx  eax,byte ptr [edx+0x2]  8048417:   0f b6 0d 5e 85 04 08    movzx  ecx,byte ptr ds:0x804855e  804841e:   29 c8                   sub    eax,ecx  8048420:   75 0d                   jne    804842f <abscompare2+0x3f>  8048422:   0f b6 42 03             movzx  eax,byte ptr [edx+0x3]  8048426:   0f b6 15 5f 85 04 08    movzx  edx,byte ptr ds:0x804855f  804842d:   29 d0                   sub    eax,edx  804842f:   5d                      pop    ebp  8048430:   c3                      ret     

is there possibility compare short literal directly without detour of embedding chr_p union, because want compare chr_p @ arbitrary indices "&chr_p[1]"?

no there not. aware compiler use knowledge strcmp? achieve (removing call overhead) without having resort type-punning in source. these kind of code transformations done in code generator after compiler has taken benefit alias analysis.

if use gcc -o3 compile following program, there no call strcmp found.

#include <string.h>  int main(int argc, char ** argv) {         return strcmp(argv[0], "abs"); } 

my x86 assembly example looked (gcc version 4.3.2 (debian 4.3.2-1.1)) (i know it's old):

main:         leal    4(%esp), %ecx         andl    $-16, %esp         pushl   -4(%ecx)         pushl   %ebp         movl    %esp, %ebp         pushl   %ecx         movl    4(%ecx), %eax         movl    (%eax), %edx         movzbl  (%edx), %eax         subl    $97, %eax         jne     .l2         movzbl  1(%edx), %eax         subl    $98, %eax         jne     .l2         movzbl  2(%edx), %eax         subl    $115, %eax         jne     .l2         movzbl  3(%edx), %eax .l2:         popl    %ecx         popl    %ebp         leal    -4(%ecx), %esp         ret 

basically strcmp has been inlined , unrolled. of course highly depends on code generator target. if not evolved enough yet, may still generate strcmp. still makes wonder if should burden ugly code, if maybe code generator support later .. when still stuck code.


Comments