在C++中存储非nul终止的C字符串常量

Adr*_*ian 7 c++ string null-character

在任何人说,"不要这样做,因为它真的很糟糕".

  1. 我理解NUL终止字符串的原因.
  2. 我知道可以陈述类似的东西
    char mystr[] = { 'm', 'y', ' ', 's', 't', 'r', 'i', 'n', 'g'};
    但是,c-string表示的便利性太大了.

这样做的理由是我正在为微控制器编程,我需要将数据存储到程序的内存中.一些数据是字节,单词,双字和浮点数的形式.我希望数据包含没有NUL连续的字符串.

我已经尝试了将<size_t N,char*A><size_t N,char(&A)[N]>作为参数的模板,以便遍历数组并将其内容存储到静态数组中,但我不能似乎做对了.我认为标准可能实际上不允许这种情况在一般情况下是可以理解的,但在特定情况下是不幸的(具体来说,这个.;):()

如果我可以将字符串重新映射为类似boost :: mpl :: vector_c <char,...>模板的东西,那会更好,因为我有其他代码可以正确存储它,但是从模板中取消引用数组到用作const模板参数似乎也是不允许的.

有任何想法吗?

编辑:

Psudocode示例(这有点人为,因为实际代码要大得多,我也不会像这样逐字节读取,也不会使用文字迭代到字符串的末尾.这将嵌入到数据以及某处.):

// this stores bytes in an array
template<typename X, typename T, T ...numbers>
struct x
{
  static PROGMEM volatile const T data[];
};
template<typename X, typename T, T ...numbers>
PROGMEM volatile const T x<X, T, numbers...>::data[] = { numbers... };

void main()
{
  // this will not work, but the idea is you have byte 0 as 1, 
  // byte 1 as 2 byte 2 as 3 byte 3 as 's', byte 4 as 'o'...
  // byte 22 as 'g', byte 23 as 4, byte 24 as 5, byte 25 as 6.
  typedef x<int, char, 1,2,3,"some embedded string",4,5,6> xx;
  for(i=0; i<20; ++i)
    Serial.print(pgm_read_byte_near(&xx::data[0] + 3));
}
Run Code Online (Sandbox Code Playgroud)

另请注意,我没有使用C++ 11,这是C++ 0x,可能还有扩展.

Use*_*ess 3

第三次尝试

魔术和诡计

如果您使用的是 C++11(我知道,但在没有它的情况下,我认为代码生成是您最好的选择),感觉用户定义的文字应该能够处理这个问题。例如,与:

template <char... RAW>
inline constexpr std::array<char, sizeof...(RAW)> operator "" _fixed() {
    return std::array<char, sizeof...(RAW)>{RAW...};
}
Run Code Online (Sandbox Code Playgroud)

如果这有效的话那就太好了:

const std::array<char, 7> goodbye = goodbye_fixed;
Run Code Online (Sandbox Code Playgroud)

...但遗憾的是事实并非如此(文字需要是数字,大概是出于解析原因)。使用"goodbye"_fixed也不起作用,因为这需要重载operator "" _fixed(const char *s, int length)并且编译时数组已再次衰减为指针。

最终我们归结为调用这个:

const auto goodbye = operator "" _FS <'g','o','o','d','b','y','e'>();
Run Code Online (Sandbox Code Playgroud)

它并不比丑陋的第一个版本更好。还有其他想法吗?


第二次尝试

自动生成丑陋

我认为你是对的,你不能轻易拦截字符串文字机制。老实说,通常的方法是使用构建工具在单独的文件中为您生成丑陋的代码(例如,参见国际化库)。

例如,您输入

fixed_string hello = "hello";
Run Code Online (Sandbox Code Playgroud)

或专用文件中的类似内容,构建系统会生成一个标头

const std::array<char, 5> hello;
Run Code Online (Sandbox Code Playgroud)

以及一个从上面到下面都有丑陋初始化的 cpp 。


第一次尝试

错过了“看起来像字符串文字”的要求

我尝试过模板...

像这样?

#include <array>
const std::array<char, 5> hello = { 'h', 'e', 'l', 'l', 'o' };

#include <cstdio>
int main()
{
    return std::printf("%.*s\n", hello.size(), &hello.front());
}
Run Code Online (Sandbox Code Playgroud)

如果您没有 C++11,Boost.Array 也可以使用,或者您也可以自己开发。请注意,这只是 的类型包装器const char[5],因此应该可以进入数据段(我已确认它.rodata与我的本地 gcc 一起进入)。