gpt4 book ai didi

c - 如何有效地将字符串与短字符串文字进行比较

转载 作者:太空狗 更新时间:2023-10-29 15:20:03 26 4
gpt4 key购买 nike

如果我不想调用 strcmp 所需的开销,我将按照以下代码示例中描述的方式将字符串与短字符串文字进行比较:

#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 with "abs"
{
if (*((ulong*) &chr_p[1]) ==
BytesAsDWord_M('a', 'b', 's', '\0'))
return true;

return false;
}

只要我在没有启用优化选项的情况下编译,gcc 就会编译这个例子。启用优化后,我收到警告:

“解引用类型双关指针将打破严格的别名规则”

即使使用 -O3 进行优化也不会产生有效的代码,如示例所示:

//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;

i = AbsCompare1(argv[0]);
j = AbsCompare2(argv[0]);

return i + 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

是否有可能直接比较这个短文字而不绕道将 chr_p 嵌入到 union 中,特别是因为我想比较任意索引处的 chr_p,如“&chr_p[1]”?

最佳答案

不,没有。您是否知道编译器将使用其关于 strcmp 的知识?它将完全按照您的意愿实现(消除调用开销),而无需诉诸源代码中的类型双关。在编译器从别名分析中获得所有好处后,这些类型的代码转换通常在代码生成器中完成。

如果我使用 gcc -O3 编译以下程序,则找不到对 strcmp 的调用。

#include <string.h>

int main(int argc, char ** argv)
{
return strcmp(argv[0], "abs");
}

例如,我的 x86 程序集看起来像这样(gcc 版本 4.3.2(Debian 4.3.2-1.1))(我知道它很旧):

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

基本上 strcmp 已经内联和展开了。当然,它在很大程度上取决于您的目标的代码生成器。所以如果它还不够进化,那么它仍然可能生成一个strcmp。仍然让你想知道你是否应该用丑陋的代码来负担自己,如果代码生成器稍后会支持这个......当你仍然坚持你的代码时。

关于c - 如何有效地将字符串与短字符串文字进行比较,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16394103/

26 4 0
文章推荐: c - 将二进制搜索展平为有序的单链表 [C]
文章推荐: html - 如何在固定高度
的中间垂直对齐 ?