简体   繁体   English

定义一个没有终止符的 C++ 字符数组

[英]Define a C++ char array without terminator

Answers to Why this program compiles fine in C & not in C++? 为什么这个程序在 C 中编译得很好,而不是在 C++ 中编译? explain that unlike the C language, the C++ language does not tolerate an initializer string for a char array that is not long enough to hold the terminating null character.解释一下,与 C 语言不同,C++ 语言不能容忍长度不足以容纳终止空字符的char数组的初始值设定项字符串。 Is there a way to specify an unterminated char array in C++ without bloating the string by a factor of four in the source code?有没有办法在 C++ 中指定一个未终止的char数组,而不会在源代码中使字符串膨胀四倍?

For example, in C and in C++, the following are equivalent:例如,在 C 和 C++ 中,以下是等效的:

const char s[] = "Hello from Stack Overflow";
const char s[] = {'H','e','l','l','o',' ','f','r','o','m',' ','S','t','a','c','k',' ','O','v','e','r','f','l','o','w','\0'};

Because the string "Hello from Stack Overflow" has length 25, these produce a 26-element char array, as if the following had been written:因为字符串"Hello from Stack Overflow"长度为 25,所以它们会生成一个 26 元素的char数组,就好像已经编写了以下内容:

const char s[26] = "Hello from Stack Overflow";
const char s[26] = {'H','e','l','l','o',' ','f','r','o','m',' ','S','t','a','c','k',' ','O','v','e','r','f','l','o','w','\0'};

In C only, a program can exclude the terminating null character, such as if the string's length is known out of band.仅在 C 中,程序可以排除终止空字符,例如如果字符串的长度是带外已知的。 (Look for "including the terminating null character if there is room" in chapter 6.7.9 of the C99 standard.) (在 C99 标准的第 6.7.9 章中查找“如果有空间,则包括终止空字符”。)

const char s[25] = "Hello from Stack Overflow";
const char s[25] = {'H','e','l','l','o',' ','f','r','o','m',' ','S','t','a','c','k',' ','O','v','e','r','f','l','o','w'};

But in C++, only the second is valid.但是在 C++ 中,只有第二个是有效的。 If I know I will be manipulating the data with functions in the std::strn family, not the std::str family, is there a counterpart in the C++ language to the shorthand syntax of C?如果我知道我将使用std::strn系列中的函数操作数据,而不是std::str系列,那么 C++ 语言中是否有与 C 的速记语法对应的函数?

My motivation differs from that of the other question about unterminated char arrays in C++ .我的动机与关于 C++ 中未终止char数组另一个问题的动机不同。 What motivates this is that several names of items in a game are stored in a two-dimensional char array.这样做的动机是游戏中的几个项目名称存储在二维char数组中。 For example:例如:

const char item_names[][16] = {
    // most items omitted for brevity
    "steel hammer",
    {'p','a','l','l','a','d','i','u','m',' ','h','a','m','m','e','r'}
};

If there is no shorthand to declare an unterminated char array, then maximum-length names will have to be written character-by-character, which makes them less readable and less maintainable than to shorter names.如果没有简写来声明一个未终止的char数组,那么最大长度的名称将不得不逐个字符地写入,这使得它们的可读性和可维护性低于较短的名称。

It is possible but I would agree with Alan Stokes' "Why"这是可能的,但我同意艾伦斯托克斯的“为什么”

For example using C++: Can a macro expand "abc" into 'a', 'b', 'c'?例如使用C++:宏可以将“abc”扩展为“a”、“b”、“c”吗? It could be tweaked father to allow operate on any provided array and constrain it by length 16.它可以被调整为允许对任何提供的数组进行操作并限制它的长度为 16。

#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>

template <unsigned int N>
constexpr char get_ch (char const (&s) [N], unsigned int i)
{
    return i >= N ? '\0' : s[i];
}

#define STRING_TO_CHARS_EXTRACT(z, n, data) \
    BOOST_PP_COMMA_IF(n) get_ch(data, n)

#define STRING_TO_CHARS(STRLEN, STR)  \
    BOOST_PP_REPEAT(STRLEN, STRING_TO_CHARS_EXTRACT, STR)


const char item_names[][16] = { // most items omitted for brevity
    "steel hammer",
    STRING_TO_CHARS(16, "palladium hammer"),
    //{'p','a','l','l','a','d','i','u','m',' ','h','a','m','m','e','r'},
};

but it could cost you more trouble in a long run...但从长远来看,这可能会给你带来更多麻烦......

the disadvantage of c-style array is that it can not be passed to or returned from functions (pass or return char* can give you an array of char* but not array of char[] in the end), we can use std::array to get around this c 风格数组的缺点是它不能传递给函数或从函数返回(传递或返回 char* 可以给你一个 char* 的数组,但最后不能给你一个 char[] 的数组),我们可以使用 std: :array 来解决这个问题
the advantage of c-style array is that small string literal can be used to initialize larger char[] in a char[][]'s initialize list (as in your example), for std::array we use std::max to simulate this c 样式数组的优点是小字符串文字可用于在 char[][] 的初始化列表中初始化较大的 char[](如您的示例),对于 std::array 我们使用 std::max模拟这个

#include<array>
#include<utility>
#include<algorithm>
#include<iostream>

template<size_t string_length, typename T, T... ints, size_t string_literal_size>
constexpr std::array<char, string_length> generate_string_impl(std::integer_sequence<T, ints...> int_seq, char const(&s)[string_literal_size])
{
    return { {s[ints]...} };
}

template<size_t string_length, size_t string_literal_size>
constexpr std::array<char, string_length> generate_string(char const(&s)[string_literal_size])
{
    return generate_string_impl<string_length>(std::make_index_sequence<string_literal_size - 1>{}, s);
}

template<size_t ...string_literals_size>
constexpr std::array < std::array<char, std::max({ string_literals_size... }) - 1 > , sizeof...(string_literals_size) > generate_array_of_strings(char const(&...s)[string_literals_size])
{
    return { generate_string < std::max({ string_literals_size... }) - 1 > (s)... };
}

int main()
{
    constexpr auto array_of_string1 = generate_array_of_strings("1234", "12345", "123456");
    //std::array<std::array<char,6>,3>{{
    //  {{ '1', '2', '3', '4', '\0', '\0' }},
    //  {{ '1', '2', '3', '4', '5', '\0' }},
    //  {{ '1', '2', '3', '4', '5', '6' }}
    //}}

    //std::array<std::array<char,6>,3> satisfies StandardLayoutType requirement
    char const(&array_of_string2)[std::size(array_of_string1)][6] = reinterpret_cast<char const(&)[std::size(array_of_string1)][6]>(array_of_string1);
    char const(*p_array_of_string2)[std::size(array_of_string1)][6] = reinterpret_cast<char const(*)[std::size(array_of_string1)][6]>(&array_of_string1);

    for (int i = 0; i != 3; ++i)
    {
        for (int j = 0; j != 6; ++j)
        {
            std::cout << i << "," << j << " " << array_of_string2[i][j] << " " << (*p_array_of_string2)[i][j] << std::endl;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM