strcmp 表示空字符串

发布于 2024-11-11 16:07:04 字数 233 浏览 5 评论 0 原文

我正在审查一些代码,我看到有人做了 a

if (0 == strcmp(foo,""))

我很好奇,因为我认为这样做会更快

if (foo[0] == '\0')

这是正确的还是 strcmp 优化得足以使它们相同。

(我意识到即使有一些差异也会很小,但我认为您使用我的方法至少可以节省一些说明。)

I was reviewing some code and I saw someone do a

if (0 == strcmp(foo,""))

I am curious because I think it would be faster to do a

if (foo[0] == '\0')

Is this correct or is strcmp optimized enough to make them the same.

(I realize that even if there was some difference it would be small, but am thinking you save at least a few instructions by using my method.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

蓝梦月影 2024-11-18 16:07:04

你是对的:由于调用 strcmp() 添加了堆栈管理和内存跳转到实际的 strcmp 指令,因此只需检查字符串的第一个字节即可获得一些指令。

出于好奇,您可以在此处检查 strcmp() 代码: http://sourceware.org/git/?p=glibc.git;a=blob;f=string/strcmp.c;h=bd53c05c6e21130b091bd75c3fc93872dd71fe4b;hb=HEAD

(我认为代码将填充 #ifdef 并且晦涩难懂__GNUSOMETHING,但实际上相当简单!)

You're right: since calling strcmp() adds up the stack management and the memory jump to the actual strcmp instructions, you'll gain a few instructions by just checking the first byte of your string.

For your curiosity, you can check the strcmp() code here: http://sourceware.org/git/?p=glibc.git;a=blob;f=string/strcmp.c;h=bd53c05c6e21130b091bd75c3fc93872dd71fe4b;hb=HEAD

(I thought the code would be filled with #ifdef and obscure __GNUSOMETHING, but it's actually rather simple!)

阳光下慵懒的猫 2024-11-18 16:07:04

strcmp() 是一个函数调用,因此具有函数调用开销。 foo[0] 是直接访问数组,所以显然更快。

strcmp() is a function call and thus has a function call overhead. foo[0] is direct access to the array, so it's obviously faster.

两仪 2024-11-18 16:07:04

我认为在这种情况下使用 strcmp 没有任何优势。编译器可能足够聪明,可以优化它,但它不会比直接检查“\0”字节快。这个的实现者可能选择了这个结构,因为他认为它更具可读性,但我认为在这种情况下这是一个品味问题。尽管我写的检查有点不同,因为这似乎是最常用于检查空字符串

if( !*str )

if( *str )

检查非空字符串的习惯用法。

I see no advantage of using strcmp in this case. The compiler my be clever enough to optimize it away but it won't be any faster than checking for the '\0' byte directly. The implementer of this might have chosen this construct because he thought it is more readable but I think this is a matter of taste in this case. Although I would write the check a little different as this is the idiom that seems to be used most often to check for an empty string:

if( !*str )

and

if( *str )

to check for a non empty string.

叹倦 2024-11-18 16:07:04

+1 Gui13提供了gcc stdlib strcmp源的链接(http://sourceware.org/git/?p=glibc.git;a=blob;f=string/strcmp.c;h=bd53c05c6e21130b091bd75c3fc93872dd71fe4b;hb =头)!

你是对的,strcmp 永远不会比直接比较更快[1],但问题是,编译器会优化它吗?我很害怕尝试测量它,但我惊喜地发现它是如此简单。我的示例代码是(省略标头):

bool isEmpty(char * str) {
   return 0==std::strcmp(str,"");
}
bool isEmpty2(char * str) {
   return str[0]==0;
}

我尝试编译该代码,首先使用 gcc -S -o-emptystrcmptest.cc,然后使用 gcc -S -O2 -o-emptystrcmptest.cc 。令我惊喜的是,虽然我不能很好地阅读程序集,但未优化的版本清楚地显示出差异,而优化的版本清楚地显示两个函数生成了相同的程序集。

所以,我想说,一般来说,担心这种程度的优化是没有意义的。

如果您正在使用嵌入式系统的编译器,并且知道它不能处理这种简单的优化(或者根本没有标准库),请使用手动编码的特殊情况版本。

如果您正常编码,请使用更具可读性的版本(恕我直言,根据上下文可能是 strcmp 或 strlen 或 [0]==0 )。

如果您正在编写高效的代码,您预计每秒会被调用数千或数百万次,(a)测试实际上更有效,(b)如果可读版本实际上太慢,请尝试编写一些可以编译为更好的组装。

使用gcc -S -o-emptystrcmptest.cc

            .file   "emptystrcmptest.cc"
            .section .rdata,"dr"
    LC0:
            .ascii "\0"
            .text
            .align 2
    .globl __Z7isEmptyPc
            .def    __Z7isEmptyPc;  .scl    2;      .type   32;     .endef
    __Z7isEmptyPc:
            pushl   %ebp
            movl    %esp, %ebp
            subl    $24, %esp
            movl    $LC0, 4(%esp)
            movl    8(%ebp), %eax
            movl    %eax, (%esp)
            call    _strcmp
            movl    %eax, -4(%ebp)
            cmpl    $0, -4(%ebp)
            sete    %al
            movzbl  %al, %eax
            movl    %eax, -4(%ebp)
            movl    -4(%ebp), %eax
            leave
            ret
            .align 2
    .globl __Z8isEmpty2Pc
            .def    __Z8isEmpty2Pc; .scl    2;      .type   32;     .endef
    __Z8isEmpty2Pc:
            pushl   %ebp
            movl    %esp, %ebp
            movl    8(%ebp), %eax
            cmpb    $0, (%eax)
            sete    %al
            movzbl  %al, %eax
            popl    %ebp
            ret
    emptystrcmptest.cc:10:2: warning: no newline at end of file
            .def    _strcmp;        .scl    2;      .type   32;     .endef

使用gcc -S -O2 -o-emptystrcmptest.cc

        .file   "emptystrcmptest.cc"
emptystrcmptest.cc:10:2: warning: no newline at end of file
        .text
        .align 2
        .p2align 4,,15
.globl __Z7isEmptyPc
        .def    __Z7isEmptyPc;  .scl    2;      .type   32;     .endef
__Z7isEmptyPc:
        pushl   %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %eax
        popl    %ebp
        cmpb    $0, (%eax)
        sete    %al
        movzbl  %al, %eax
        ret
        .align 2
        .p2align 4,,15
.globl __Z8isEmpty2Pc
        .def    __Z8isEmpty2Pc; .scl    2;      .type   32;     .endef
__Z8isEmpty2Pc:
        pushl   %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %eax
        popl    %ebp
        cmpb    $0, (%eax)
        sete    %al
        movzbl  %al, %eax
        ret

[1] 尽管要小心——以防万一比直接针对零进行测试复杂,库和编译器代码通常会比手工编写的代码更好。

+1 to Gui13 for providing a link to the source of gcc stdlib strcmp (http://sourceware.org/git/?p=glibc.git;a=blob;f=string/strcmp.c;h=bd53c05c6e21130b091bd75c3fc93872dd71fe4b;hb=HEAD)!

You are correct that strcmp can never be faster than a direct comparison[1], but the question is, will the compiler optimise it? I was intimidated to try measuring that, but I was pleasantly surprised at how easy it was. My sample code is (omitting headers):

bool isEmpty(char * str) {
   return 0==std::strcmp(str,"");
}
bool isEmpty2(char * str) {
   return str[0]==0;
}

And I tried compiling that, first with gcc -S -o- emptystrcmptest.cc and then with gcc -S -O2 -o- emptystrcmptest.cc. To my pleasant surprise, although I can't read the assembly very well, the non-optimised version clearly showed a difference, and the optimised version clearly showed the two functions produced identical assembly.

So, I would say that in general, there's no point worrying about this level of optimisation.

If you are using a compiler for an embedded system and know it not to handle this sort of simple optimisation (or don't have a standard library at all), use the hand-coded special-case version.

If you are coding normally, use the more readable version (imho that may be strcmp or strlen or [0]==0 depending on context).

If you are writing highly efficient code you expect to be called thousands or millions of times a second, (a) test which is actually more efficient and (b) if the readable version is actually too slow, try to write somethign which will compile to better assembly.

With gcc -S -o- emptystrcmptest.cc:

            .file   "emptystrcmptest.cc"
            .section .rdata,"dr"
    LC0:
            .ascii "\0"
            .text
            .align 2
    .globl __Z7isEmptyPc
            .def    __Z7isEmptyPc;  .scl    2;      .type   32;     .endef
    __Z7isEmptyPc:
            pushl   %ebp
            movl    %esp, %ebp
            subl    $24, %esp
            movl    $LC0, 4(%esp)
            movl    8(%ebp), %eax
            movl    %eax, (%esp)
            call    _strcmp
            movl    %eax, -4(%ebp)
            cmpl    $0, -4(%ebp)
            sete    %al
            movzbl  %al, %eax
            movl    %eax, -4(%ebp)
            movl    -4(%ebp), %eax
            leave
            ret
            .align 2
    .globl __Z8isEmpty2Pc
            .def    __Z8isEmpty2Pc; .scl    2;      .type   32;     .endef
    __Z8isEmpty2Pc:
            pushl   %ebp
            movl    %esp, %ebp
            movl    8(%ebp), %eax
            cmpb    $0, (%eax)
            sete    %al
            movzbl  %al, %eax
            popl    %ebp
            ret
    emptystrcmptest.cc:10:2: warning: no newline at end of file
            .def    _strcmp;        .scl    2;      .type   32;     .endef

With gcc -S -O2 -o- emptystrcmptest.cc:

        .file   "emptystrcmptest.cc"
emptystrcmptest.cc:10:2: warning: no newline at end of file
        .text
        .align 2
        .p2align 4,,15
.globl __Z7isEmptyPc
        .def    __Z7isEmptyPc;  .scl    2;      .type   32;     .endef
__Z7isEmptyPc:
        pushl   %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %eax
        popl    %ebp
        cmpb    $0, (%eax)
        sete    %al
        movzbl  %al, %eax
        ret
        .align 2
        .p2align 4,,15
.globl __Z8isEmpty2Pc
        .def    __Z8isEmpty2Pc; .scl    2;      .type   32;     .endef
__Z8isEmpty2Pc:
        pushl   %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %eax
        popl    %ebp
        cmpb    $0, (%eax)
        sete    %al
        movzbl  %al, %eax
        ret

[1] Although be careful -- in cases any more complicated than a direct test against zero, the library and compiler code a typically WILL be better than hand-crafted code.

橘寄 2024-11-18 16:07:04

一个好的优化编译器可能会优化函数调用,然后消除内联函数中的循环。尽管有可能速度相同,但您的方法不可能更慢。

A good optimizing compiler might optimize away the function call and then eliminate the loop from the inlined function. There's no way that your method could be slower, though there is a chance that it will be the same speed.

可爱咩 2024-11-18 16:07:04

对数组的访问在执行时间上是顺序 1,因此,它比函数更快。

Access to an array is order 1 in execution time, so, it´s faster than the function.

十年九夏 2024-11-18 16:07:04

这是微观优化,但我想如果您在索引 foo 之前添加了空检查(除非您知道它永远不会为空),那么从技术上讲,它会节省函数调用的开销。

This is as micro-optimizing as it gets, but I suppose if you added a null check before you index foo (unless you know it'll never be null) it would technically save the overhead of a function call.

情绪 2024-11-18 16:07:04

显然,它会更快,并且如果您打算继续使用它,则可能值得将您自己的代码放入内联函数,甚至可能是宏中:

int isEmpty(const char *string)
{
    return ! *string;
}

int isNotEmpty(const char *string)
{
    return *string;
}

int isNullOrEmpty(const char *string)
{
    return string == NULL || ! *string;
}

int isNotNullOrEmpty(const char *string)
{
    return string != NULL && *string;
}

并让编译器为您优化它。无论如何,strcmp 需要最终检查 '\0',以便您始终至少等于它。 (老实说,我可能会让编译器优化上述内容的内部共享,例如,isEmpty可能只是翻转isNotEmpty

It's clearly going to be faster, and it's probably worth placing your own code in an inline function, or maybe even a macro, if you plan on moving forward with it:

int isEmpty(const char *string)
{
    return ! *string;
}

int isNotEmpty(const char *string)
{
    return *string;
}

int isNullOrEmpty(const char *string)
{
    return string == NULL || ! *string;
}

int isNotNullOrEmpty(const char *string)
{
    return string != NULL && *string;
}

and let the compiler optimize that for you. Regardless, strcmp needs to eventually check for '\0' so you're always at least equal to it. (honestly, I'd probably let the compiler optimize internal sharing of the above, e.g., isEmpty would probably just flip isNotEmpty)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文