您的位置:首页 > 产品设计 > UI/UE

Arduino代码机制-WString.h

2016-02-15 21:13 417 查看
Arduino提供了一个非常有用库,用来处理字符串,支持RAM和Flash中的字符串处理。并且重载了一些运算符,使得我们可以使用==来判断两个字符串是否相等,用=来对字符串对象赋值,用+来连接两个字符串,用[]来取字符串中某个字符。但要特别注意,有些函数并不是绝对安全的,使用这些函数时要特别小心。

WString.h中有三个类,String,__ FlashStringHelper和StringSumHelper。后两个类是用来辅助String操作的。

成员变量

首先看String中的成员变量:

class String {
protected:
char *buffer;
unsigned int capacity;
unsigned int len;
};


String中有三个成员变量,指向字符串的指针buffer,能容纳的最大字符数capacity和字符串长度len。

构造方法

String提供了很多个构造方法,具体来看:

用指向字符串数组第一个字符的指针构造或者用另一个引用的对象构造

String(const char *cstr = "");
String(const String &str);
String(const __FlashStringHelper *str);


最后一个是用Flash中的字符串指针来构造。

class __FlashStringHelper;
#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))


类__FlashStringHelper中没有任何东西,它就是单纯的用来处理Flash指针的。

PSTR(string_literal)将字符串放在Flash中,宏的结果是一个指向Flash中字符串string_literal的指针,然后使用C++关键字reinterpret_case将字符串指针强制转换成const __FlashStringHelper类型的指针。这种类型的指针即第三个构造函数的参数。

所以可以用宏F来构造String:

String *s = new String(F("abc"));


那么这就是用Flash中的字符串”abc”来构造String。

这个构造函数固然比较好,但是我们不能用一个指向Flash的指针来构造String,但用这样的指针来构造函数是我们更需要的。我们不可能向构造函数中传入Flash指针,因为构造函数不可能知道这个指针是指向RAM还是指向Flash。

如果想要用Flash指针构造String的话要怎么办呢?可以强制类型转换,手动将字符串指针转换为const __FlashStringHelper类型的指针。

const char *FlashString = PSTR("string in flash");
String *str = new String((const __FlashStringHelper*)FlashString);


用数字构造String,这时候就需要设定数字的进制。还用explicit关键字限定构造函数只能被显式调用。

explicit String(char c);
explicit String(unsigned char, unsigned char base=10);
explicit String(int, unsigned char base=10);
explicit String(unsigned int, unsigned char base=10);
explicit String(long, unsigned char base=10);
explicit String(unsigned long, unsigned char base=10);
explicit String(float, unsigned char decimalPlaces=2);
explicit String(double, unsigned char decimalPlaces=2);


重载运算符

WString对=,==,>, >=, <,<=, +, +=进行了重载

=

等号能进行三种赋值操作

String & operator = (const String &rhs);
String & operator = (const char *cstr);
String & operator = (const __FlashStringHelper *str);


由于重载了等号,我们就对String类型赋值就可以这样:

String s("abc");//调用构造函数

String s1;s1 = "abc";//调用重载运算符
String s2;s2 = s;//调用重载运算符
String s3;s3 = PSTR("abc");//调用重载运算符


==

==只重载了两种类型的比较

unsigned char operator == (const String &rhs);
unsigned char operator == (const char *cstr);


因此==不能与Flash中字符串比较

+=

这个运算符可能需要扩大当前对象buffer的容量(capacity),在这种情况下,如果申请额外内存失败,则不会改变当前对象,也就是并不会计算+=,而且也不会给出提示。因此这个运算符不安全,尽量不要使用,建议使用concat。

String & operator += (const String &rhs);
String & operator += (const char *cstr);
String & operator += (char c);
String & operator += (unsigned char num);
String & operator += (int num);
String & operator += (unsigned int num);
String & operator += (long num) ;
String & operator += (unsigned long num);
String & operator += (float num);
String & operator += (double num);
String & operator += (const __FlashStringHelper *str);


其他的运算符重载在源文件中查看。

实用函数

concat

String类重载了很多个concat函数。相对于+=来说,这个是安全的。因为当内存不足字符串拼接失败是会返回false,只有拼接成功才返回true。使用这个函数时,应当要检查字符串是否拼接成功。

unsigned char concat(const String &str);
unsigned char concat(const char *cstr);
unsigned char concat(char c);
unsigned char concat(unsigned char c);
unsigned char concat(int num);
unsigned char concat(unsigned int num);
unsigned char concat(long num);
unsigned char concat(unsigned long num);
unsigned char concat(float num);
unsigned char concat(double num);
unsigned char concat(const __FlashStringHelper * str);


获取和设置当前对象指定位置处的字符

char charAt(unsigned int index) const;
void setCharAt(unsigned int index, char c);


这比较容易理解。同时还可以通过运算符[]来实现:

char operator [] (unsigned int index) const;
char& operator [] (unsigned int index);


还可以获得当前存储的字符串,可以存入新的字符数组中,也能直接返回buffer指针。

void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const;//从当前对象的buffer中获取bufsize个字符转换成无符号字符型存入buf的index处。
void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0);//从当前对象的buffer中获取bufsize个字符存入buf的index处。
const char * c_str();//直接返回buffer。


查找

int indexOf( char ch ) const;//在当前对象中查找字符ch,返回ch第一次出现的位置在字符串中的索引
int indexOf( char ch, unsigned int fromIndex ) const;//从fromIndex处开始在当前对象中查找字符ch,返回ch第一次出现的位置在字符串中的索引

int indexOf( const String &str ) const;//在当前对象中查找字符串str,返回str第一次出现的位置在字符串中的索引
int indexOf( const String &str, unsigned int fromIndex ) const;//从fromIndex处开始在当前对象中查找字符str,返回str第一次出现的位置在字符串中的索引


还有LastIndexOf函数,与indexOf类似

int lastIndexOf( char ch ) const;
int lastIndexOf( char ch, unsigned int fromIndex ) const;
int lastIndexOf( const String &str ) const;
int lastIndexOf( const String &str, unsigned int fromIndex ) const;


子字符串

String substring( unsigned int beginIndex ) const;//获取从beginIndex到结尾的子字符串
String substring( unsigned int beginIndex, unsigned int endIndex ) const;//获取从beginIndex到endIndex之间的字符串。


替换

void replace(char find, char replace);
void replace(const String& find, const String& replace);//将所有字符或字符串find用replace替换

void remove(unsigned int index);//移除index以后所有字符
void remove(unsigned int index, unsigned int count);//从index开始移除count个字符。

void toLowerCase(void);
void toUpperCase(void);
void trim(void);//去掉字符串开头和结尾处的空格


转换

这两个函数非常有用,将字符串转换为整形或者浮点型数字

long toInt(void) const;
float toFloat(void) const;


可能造成隐患的函数

unsigned char String::reserve(unsigned int size)
{
if (buffer && capacity >= size) return 1;
if (changeBuffer(size)) {
if (len == 0) buffer[0] = 0;
return 1;
}
return 0;
}

unsigned char String::changeBuffer(unsigned int maxStrLen)
{
char *newbuffer = (char *)realloc(buffer, maxStrLen + 1);
if (newbuffer) {
buffer = newbuffer;
capacity = maxStrLen;
return 1;
}
return 0;
}


函数reserve用来判断当前String对象能不能容纳下长度为size的字符串,如果能则返回1,如果不能则通过ChangeBuffer函数扩大buffer(可能会改变内存地址)。如果成功申请到了内存则扩大buffer并返回1,如果申请内存失败则返回0。

reserve函数又被copy函数调用,copy函数将RAM中字符串或者Flash中字符串复制到buffer指向的内存中。由于要复制的字符串长度可能大于buffer缓冲的长度(capacity),就有可能会申请内存。当申请失败时,copy函数会将buffer置为空指针并释放内存。其中一个copy函数为:

String & String::copy(const char *cstr, unsigned int length)
{
if (!reserve(length)) {
invalidate();
return *this;
}
len = length;
strcpy(buffer, cstr);
return *this;
}


只要有可能改变buffer长度的函数都调用了这三个函数,为了安全,使用这些函数以后,要确定是否完成了操作。

1.当将一个很大的字符串尤其是位于Flash中的字符串赋值给String类型后(在RAM较小的单片机里申请连续的上百个字节的内存是很有可能申请失败的),检查buffer是否为空指针。

if(reserve(0))//已经赋值


2.concat函数也可能需要扩大容量,也可能会申请内存失败。如果concat失败则函数返回false。

String s = "123";
if(s.concat(1323))//拼接成功
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: