Why this program compiles fine in C & not in C++?的答案解释说,与C语言不同,C ++语言不允许char
数组的初始化字符串不足以容纳终止空字符。有没有办法在C ++中指定一个未终止的char
数组,而不会在源代码中将字符串膨胀四倍?
例如,在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'};
因为字符串"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'};
仅在C中,程序可以排除终止空字符,例如字符串的长度是否在带外已知。 (在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'};
但是在C ++中,只有第二个是有效的。如果我知道我将使用std::strn
系列中的函数而不是std::str
系列来操作数据,那么C ++语言中是否存在与C的简写语法相对应的数据?
我的动机与other question about unterminated char
arrays in C++的动机不同。激发这一点的是,游戏中的几个项目名称存储在二维char
数组中。例如:
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'}
};
如果没有简写来声明未终止的char
数组,那么必须逐个字符地写入最大长度的名称,这使得它们比较短的名称更易于阅读和维护。
答案 0 :(得分:0)
这是可能的,但我同意艾伦斯托克斯' "为什么"
例如使用C++: Can a macro expand "abc" into 'a', 'b', 'c'? 它可以被调整为父,以允许对任何提供的数组进行操作,并将其约束为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'},
};
但从长远来看,这可能会给你带来更多麻烦......
答案 1 :(得分:0)
c 样式数组的缺点是不能传递给函数或从函数返回(传递或返回 char* 可以给你一个 char* 的数组,但最后不能给你一个 char[] 的数组),我们可以使用 std::array 来解决这个问题
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;
}
}
}