在 c++ 中获取常量字符 * 长度的最佳方法

Best way to get length of const char * in c++

本文关键字:最佳 方法 字符 c++ 获取 常量      更新时间:2023-10-16

我知道有两种方法可以获取常量字符的长度 *

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

其他方式很简单

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

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

让我们检查一下这两个方法的程序集列表。

#include <cstddef>
#include <cstring>
int string_size_1()
{
    const char * str = "Hello World !";
    int Size = 0;
    while (str[Size] != '') Size++;
    return Size;
}
int string_size_2()
{
    const char * str = "Hello World !";
    size_t Size = strlen(str);
    return Size;
}

将 Clang 4.0.0 与标志一起使用-std=c++14 -O2

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字符串更可取。考虑一下它们。

在这种情况下,答案在编译时是已知的:

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::d istance,如果处理 std::string 则使用 .size((

迟到 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: %lun", length(myStrings));
    printf("Length of myNums array: %lun", length(myNums));
    printf("Length of myChars array: %lun", length(myChars));
    return 0;
    /* Output:
           Length of myStrings array: 3
           Length of myNums array: 5
           Length of myChars array: 7 */
}

我测试了它,它也适用于未初始化的数组,可能是因为它们包含来自同一类型的垃圾(来自未初始化(。整数未初始化数组包含随机整数,常量字符* 未初始化数组包含 (null(,它被视为常量字符*。

现在,这仅适用于堆栈上的数组。指向用作数组的堆中保留的空间的指针将产生意外结果。例如:

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

所以请注意。反正谁在堆上使用数组,所以随便。

注意:这与此问题有关,因为它可以根据要求与常量字符*一起使用。也适用于其他类型的。