在C ++中存储非nul终止的C字符串常量 [英] store non-nul terminated C string constant in C++

查看:219
本文介绍了在C ++中存储非nul终止的C字符串常量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在任何人说不要这样做,因为它真的很糟糕之前。



  1. 我知道可以指定类似

     char mystr [] = {'m','y','','s ','t','r','i','n','g'}; 


    然而,c字符串表示的方便性太大了。 li>

这是我编程微控制器的理由,我需要将数据存储到程序的内存中。一些数据是以字节,字,双字和浮点的形式。



我尝试过使用< size_t N,char * A> < size_t N,char(& A)[N]> 作为参数,以便遍历数组并将其内容存储到静态数组,修正它。我认为标准可能实际上不允许这在一般情况下是可以理解的,但不幸在特定情况下(具体来说,这一个。):()



如果我可以将字符串重新映射为像一个 boost :: mpl :: vector_c< char,...> 模板,这将是更好的,因为我有其他代码将正确存储,但解除引用一个数组



任何想法?



编辑:



Psudocode示例(这是一种设计,因为真正的代码更大,也不可能逐字节读取这个,我也不会使用字面值来迭代到字符串的结尾,这将被嵌入在数据以及某处。):

  //这在数组中存储字节
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()
{
//这不会工作,但是你的想法是字节0为1,
//字节1为2字节2为3字节3为's',字节4为'o'...
//字节22为'g',字节23为4,字节24为5,字节25为6.
typedef x< int,char,1,2,3,一些嵌入字符串,4,5,6> xx;
for(i = 0; i <20; ++ i)
Serial.print(pgm_read_byte_near(& xx :: data [0] + 3));
}

还要注意,我不使用C ++ 11,这是C + + 0x,可能还有一个扩展名。

解决方案

第三次尝试



< 魔法和欺骗



如果你使用的是C ++ 11(我知道,但在缺席的时候我认为代码生成是你最好的选择) ,感觉就像一个用户定义的文字应该能够处理这个。例如:

 模板< char ... RAW> 
inline constexpr std :: array< char,sizeof ...(RAW)>运算符_fixed(){
return std :: array< char,sizeof ...(RAW)> {RAW ...}
}

这将是很好,如果这工作:

  const std :: array< char,7> goodbye = goodbye_fixed; 

...但可悲的是它不是(字面值需要是数字的,可能是解析的原因)。使用goodbye_fixed 也不工作,因为这需要一个运算符_fixed(const char * s,int length)

最后,我们来调用这个:

  const auto goodbye = operator_FS<'g','o','o','d','b' e'(); 

它不比丑陋的第一个版本更好。任何其他想法?






第二次尝试



自动生成丑陋



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



例如,您键入

  fixed_string hello =hello 

或类似的专用文件,并且构建系统生成头

  const std :: array< char,5>你好; 

和一个cpp,从上面 >




首先尝试



错过了文字要求




我已尝试过模板...


像这样?

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

#include< cstdio>
int main()
{
return std :: printf(%。* s\\\
,hello.size(),&hello.front());
}



如果你没有C ++ 11,Boost.Array会工作,或者你可以自己滚。
注意,这只是一个类型包装器 const char [5] ,所以应该确定进入数据段 .rodata 与我的本地gcc)。


Before anyone says, "DON'T DO THIS as it is really bad".

  1. I understand the reasons for having a NUL terminated string.
  2. I know one can state something like

    char mystr[] = { 'm', 'y', ' ', 's', 't', 'r', 'i', 'n', 'g'};

    However, the convenience of the c-string representation is too great.

The rational for this is that I'm programming for a micro-controller and I need to store data into the programme's memory. Some of the data is in the form of bytes, words, dwords and floats. I'd like the data to include strings without the NUL contiguously.

I've tried templates that take <size_t N, char* A> and <size_t N, char (&A)[N]> as parameters in order to traverse the array and store its contents to a static array, but I can't seem to get it right. I think the standard may actually disallow this which is understandable in the general case, but unfortunate in specific cases (specifically, this one. ;) :( )

If I could remap the string as something like a boost::mpl::vector_c<char, ...> template, that would be better as I have other code that will store it properly, but dereferencing an array from within a template to be used as a const template parameter appears to be disallowed too.

Any ideas?

EDIT:

Psudocode example (this is kinda contrived as the real code is much larger, also I wouldn't probably read byte by byte like this, nor would I be using a literal to iterate to the end of the string. That would be embedded in the data as well somewhere.):

// 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));
}

Also note that I am not using C++11, this is C++0x, and possibly an extension.

解决方案

Third try

magic and trickery

If you were using C++11 (I know, but in its absence I think code generation is your best bet), it feels like a user-defined literal should be able to handle this. Eg, with:

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

it would be nice if this worked:

const std::array<char, 7> goodbye = goodbye_fixed;

... but sadly it doesn't (the literal needs to be numeric, presumably for parsing reasons). Using "goodbye"_fixed doesn't work either, as that requires an operator "" _fixed(const char *s, int length) overload and the compile-time array has decayed to a pointer again.

Eventually we come down to invoking this:

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

and it's no better than the ugly first version. Any other ideas?


Second try

auto-generate the ugliness

I think you're right that you can't easily intercept the string literal mechanism. Honestly, the usual approach would be to use a build tool to generate the ugly code for you in a separate file (cf. internationalization libraries, for example).

Eg, you type

fixed_string hello = "hello";

or something similar in a dedicated file, and the build system generates a header

const std::array<char, 5> hello;

and a cpp with the ugly initialization from above below.


First try

missed the "looks like a string literal" requirement

I've tried templates ...

like this?

#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());
}

If you don't have C++11, Boost.Array will work, or you can roll your own. Note that this is just a type wrapper around const char[5], so should be ok to go in the data segment (I've confirmed it goes in .rodata with my local gcc).

这篇关于在C ++中存储非nul终止的C字符串常量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆