【问题标题】:Best way to get length of const char * in c++在 C++ 中获取 const char * 长度的最佳方法
【发布时间】:2017-11-25 04:24:12
【问题描述】:

我知道两种获取 const char * 长度的方法

const char * str = "Hello World !";
int Size = 0;
while (str[Size] != '\0') Size++;

其他方式很简单

const char * str = "Hello World !";
size_t Size = strlen(str);

但我不想使用像 strlen 这样的 str lib 函数,而且我认为这个函数也使用了我的第一种方式行为。因为在 pc 世界中,当我们想要计算一些东西时,我们需要计算每个块的长度,并且没有魔法可以通过一个动作来获得长度,所以我认为第一种方法是获得 const char * 长度的最佳选择。其他方式我认为第一种方式对于重弦可能太重了。所以我很困惑。哪种方式更好,为什么其他方式不是?

【问题讨论】:

  • 标准库中的某些东西几乎总是比您自己编写代码来做同样事情的任何东西都快,而且肯定不太可能出现错误。
  • 这两个示例是等价的,但strlen 可能会更快,因为编译器特定的东西,并且无论如何最好使用已经为您编写的代码。
  • 你为什么不想使用strlen()
  • 另外,既然是C++,只要使用std::string,就可以使用它的size()方法。
  • 或者使用新的 std::string_view 和你的 C 字符串。

标签: c++ string-length strlen


【解决方案1】:

让我们看看这两个方法的汇编列表。

#include <cstddef>
#include <cstring>

int string_size_1()
{
    const char * str = "Hello World !";
    int Size = 0;
    while (str[Size] != '\0') Size++;
    return Size;
}

int string_size_2()
{
    const char * str = "Hello World !";
    size_t Size = strlen(str);
    return Size;
}

使用带有标志 -std=c++14 -O2 的 Clang 4.0.0

string_size_1():                     # @string_size_1()
        mov     eax, 13
        ret

string_size_2():                     # @string_size_2()
        mov     eax, 13
        ret

链接:https://godbolt.org/g/5S6VSZ

两种方法最终得到完全相同的程序集列表。此外,编译器会优化所有内容并仅返回一个常量,因为字符串文字在编译时是已知的。因此,就性能而言,它们同样出色。

但就可读性而言,strlen(str) 肯定更好。函数调用通过函数名说明意图。循环无法做到这一点。


此外,std::stringstd::string_view 在许多情况下比 C 字符串更可取。考虑一下。

【讨论】:

  • 如果你在字符串中加入\0,你会得到相同的编译代码吗?那将是一个错误。
  • 对于第一种情况,这是一些非常奇怪的代码生成,但我想它最终会提供正确的答案。
  • @MarkRansom 这两个函数都计算出数字 13,为什么你认为优化编译器识别出这个数字很奇怪?
  • @Caleth 第一个示例比我预期的优化器在编译时处理的要复杂一些,但老实说,我不记得为什么我在 4 年前留下了该评论。
【解决方案2】:

在这种情况下,答案在编译时就知道了:

template <std::size_t S>
constexpr std::size_t string_length
(
    char const (&)[S]
)
{
    return S - 1;
}

用法:

std::cout << string_length("example") << std::endl;

对于字符串不是编译时常量的情况,如果只有指向字符串的指针可用,则使用 strlen;如果指向开头和结尾的指针都可用,则使用 std::distance;如果您处理的是 .size()一个 std::string

【讨论】:

  • 他们特别要求 const char * 作为输入,您的代码将无法使用它
  • 我的回答也解决了 char * 问题。他的示例还处理 char[] 类型,但只是通过不使用 auto 来强制衰减。问题和答案的精神都很明确。
【解决方案3】:

迟到 3 年,但迟到总比不晚。

简答

#define length(array) ((sizeof(array)) / (sizeof(array[0])))

长答案

所以使用sizeof(array) 返回the size of the type of the array * the amount of elements。知道了这一点,我们就可以做到这一点:

#define length(array) ((sizeof(array)) / (sizeof(array[0])))

你会像这样使用它:

type yourArray[] = {your, values};
length(yourArray);    // returns length of yourArray

例如:

#include <stdlib.h>
#include <stdio.h>

#define length(array) ((sizeof(array)) / (sizeof(array[0])))


int main()
{
    const char *myStrings[] = {"Foo", "Bar", "Hello, World!"};    // 3 elements
    int myNums[] = {0, 1, 5, 7, 11037};    // 5 elements
    char myChars[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g'};    // 7 elements

    printf("Length of myStrings array: %lu\n", length(myStrings));
    printf("Length of myNums array: %lu\n", length(myNums));
    printf("Length of myChars array: %lu\n", length(myChars));

    return 0;

    /* Output:
           Length of myStrings array: 3
           Length of myNums array: 5
           Length of myChars array: 7 */
}

我对其进行了测试,它也适用于未初始化的数组,可能是因为它们包含来自同一类型的垃圾(未初始化)。整数未初始化数组包含随机整数,而 const char* 未初始化数组包含 (null),它被视为 const char*。

现在,这只适用于堆栈上的数组。指向用作数组的堆中保留的空间的指针会产生意想不到的结果。例如:

int *myNums = (int *)malloc(3 * sizeof(int));    // Space for 3 integers
printf("Length of myNums: %lu\n", length(myNums));  // Outputs 2 instead of 3

所以请注意。无论如何,谁在堆上使用数组等等。

注意:这与这个问题有关,因为它可以按要求与 const char * 一起使用。也适用于其他类型。

【讨论】:

  • 当出现const char * str = "Hello World !"; length(str) 时,这在给出所需答案 13 时惨遭失败。并且“整数未初始化数组包含随机整数,而 const char* 未初始化数组包含 (null),它被视为 const char*。”具有误导性。读取未初始化值的程序具有未定义的行为,您已经观察到(在某一时刻)就好像存在任意值一样。其他症状是可能的
  • @Caleth 那是因为这个宏旨在获取堆栈中的数组的长度,而不是指针。给定const char *str[] = {"Hello World !"};,它返回正确的长度 1。无论哪种方式,我都意识到我误解了这个问题,所以这是我的错。谢谢指出
  • 是的,所以这无法回答提出的问题
  • 它并没有真正的帮助。最好的方法是在我们仍然知道它的点的附加参数中提供大小。
猜你喜欢
  • 2019-02-12
  • 1970-01-01
  • 2016-07-30
  • 2010-12-14
  • 1970-01-01
  • 1970-01-01
  • 2013-06-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多