1

我需要将一些 char * (我知道它的长度)与一些字符串文字进行比较。现在我正在这样做:

void do_something(char * str, int len) {
  if (len == 2 && str[0] == 'O' && str[1] == 'K' && str[2] == '\0') {
    // do something...
  }
}

问题是我有很多这样的比较要进行,分解并键入每个比较是非常乏味的。此外,这样做很难维护并且容易引入错误。

我的问题是是否有速记来输入这个(可能是宏)。

我知道有strncmp并且我已经看到GCC 对其进行了优化。所以,如果速记是使用strncmp,像这样:

void do_something(char * str, int len) {
  if (len == 2 && strncmp(str, "OK", len) == 0) {
    // do something...
  }
}

然后,我想知道第二个示例与第一个示例具有相同(或更好)的性能。

4

2 回答 2

1

是的,它会的。但是,您的代码没有将 achar *与字符串文字进行比较。它正在比较两个字符串文字。编译器足够聪明,可以发现这一点并优化所有代码。if仅保留块内的代码。

我们可以通过查看编译器生成的汇编代码看到这一点:

cc -S -std=c11 -pedantic -O3 test.c

首先使用您的原始代码...

#include <stdio.h>
#include <string.h>

int main() {
    unsigned int len = 2;
    char * str = "OK";
    if (len == 2 && strncmp(str, "OK", len) == 0) {
      puts("Match");
    }
}

然后只用puts.

#include <stdio.h>
#include <string.h>

int main() {
    //unsigned int len = 2;
    //char * str = "OK";
    //if (len == 2 && strncmp(str, "OK", len) == 0) {
      puts("Match");
    //}
}

这两个汇编文件实际上是相同的。没有留下任何字符串的痕迹,只有puts.

    .section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 10, 14    sdk_version 10, 14
    .globl  _main                   ## -- Begin function main
    .p2align    4, 0x90
_main:                                  ## @main
    .cfi_startproc
## %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    leaq    L_.str(%rip), %rdi
    callq   _puts
    xorl    %eax, %eax
    popq    %rbp
    retq
    .cfi_endproc
                                        ## -- End function
    .section    __TEXT,__cstring,cstring_literals
L_.str:                                 ## @.str
    .asciz  "Match"


.subsections_via_symbols

这是一个专注于优化的糟糕地方。字符串与小字符串的比较不太可能是性能问题。

此外,您建议的优化可能会更慢。您需要获取输入字符串的长度,这需要遍历输入字符串的全长。也许您出于其他原因需要它,但它的边缘情况越来越多。

strncmp一旦看到不相等的字符就可以停止。它肯定只需要读取到最小字符串的末尾。

于 2020-07-09T17:15:30.753 回答
0

您的示例意味着您的字符串始终以 NUL 结尾。在这种情况下,不要费心提前获取它们的长度,因为这涉及到搜索 NUL。相反,你可以做

memcmp(str, "OK", 3);

这样,NUL 也可以进行比较。如果您的长度 > 2,则结果将 > 0,如果长度更短,则结果将 < 0。

这是一个单一的函数调用,memcmp几乎可以保证比您的手写代码得到更好的优化。同时,除非您发现此代码是瓶颈,否则不要费心优化。还要记住,我在我的机器上运行的任何基准测试都不一定适用于你的。

进行此更改的唯一真正原因是为了可读性。

于 2020-07-10T14:37:25.763 回答