从新建工程开始使用C++开发单片机(以STM32为例):七、移植Arduino的WString(附代码)

article/2025/10/15 9:32:22

在上一篇文章中,介绍了outputString和inputString,其中所运用到的字符串类型String也是C++驱动层中功能强大且重要的一个类。这个类移植自Arduino的WString。这篇文章将会展示WString的易用性,并且从编译输出后程序大小的角度比较WSting和C++ std::string的区别,并且在后边还会有具体的移植步骤,最后还会附上全部的代码。
在这里插入图片描述

一、WString简单介绍

WString是Arduino自带的一个字符串类型,功能强大,可以实现字符串的拼接、拷贝、转换、比较等功能,是不可缺少的一项利器。熟悉Arduino的小伙伴应该对它已经非常熟悉了,下面再通过一段Arduino的代码来展示一下其功能。
关于WString的更多功能和用法可以浏览Arduino的官方文档

void setup() {Serial.begin(115200);String str1="hello ",str2="world";String str=str1+str2;Serial.print("str=str1+str2=");Serial.println(str);String str3="hello ";if(str3==str1){Serial.println("str3==str1");}int a=12345;String str4="a=";Serial.println(str4+a);String str5="54321";a=str5.toInt();Serial.println(a);
}
// the loop function runs over and over again forever
void loop() {
}

在这里插入图片描述

二、为什么不用std::string

有的小伙伴可能会问,C++已经有了功能强大的std::string,可以在项目中直接使用为什么还要移植WString?请添加图片描述
我们先来看看Arduino下使用std::string和WString生成的代码容量:
因为Arduino原生支持的板子不支持std::string,所以这里使用的板子是ESP32
首先是使用std::string:

#include<string>
void setup() {std::string str = "hello wrold";
}
// the loop function runs over and over again forever
void loop() { 
}

编译后输出为:项目使用了 249084 字节,占用了 (19%) 程序存储空间。最大为 1310720 字节。 全局变量使用了13412字节,(4%)的动态内存,余留314268字节局部变量。最大为327680字节。
再来看看使用WString:

void setup() {String str = "hello wrold";
}
// the loop function runs over and over again forever
void loop() { 
}

编译后输出为:项目使用了 197852 字节,占用了 (15%) 程序存储空间。最大为 1310720 字节。 全局变量使用了13084字节,(3%)的动态内存,余留314596字节局部变量。最大为327680字节。
通过比较后发现,使用std::string比使用WString多出了5k多的内存,这个代码的膨胀还是非常惊人的。

我们再来看看在Keil环境(处理器为STM32ZET6)下编译的代码的内存占用情况:
首先是std::string:

#include "User.h"
#include <string>
int main()
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);systick_init();adc_init();/********************************************************************/std::string str = "hello wrold";/********************************************************************/while (1){}
}

编译后输出为:Program Size: Code=15392 RO-data=1920 RW-data=148 ZI-data=63868

WString:

#include "User.h"
int main()
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);systick_init();adc_init();/********************************************************************/String str = "hello wrold";/********************************************************************/while (1){}
}

编译后输出为:Program Size: Code=2960 RO-data=336 RW-data=40 ZI-data=63832
对比两段代码的输出,不难发现std::string不管在Arduino下,还是在Keil下,内存膨胀都是非常严重的。
请添加图片描述
所以为了更高效率地运行字符串,一个高效、简洁地string是十分重要的。而目前网络上已经有了不少开源的String类,所以我们不需要再重复造轮子,移植就完事了!
在这里插入图片描述

三、移植WString

1.准备工作:
在移植之前,首先将之前几篇文章的代码全部放到相应的文件夹中。之前的文件我全都在文件头部加上了注释对文件进行解释和说明,这里我再进行一些总结:
每个文章最后附带的代码中,对应的文件名我都加到了代码的头部,例如my_usart.h:
在这里插入图片描述
在我专栏的博客下边附带的代码中:
文件名为 my_xxx.h、my_xxx.c、headfile.h、resources.h 都是C语言接口层的代码,放在项目文件夹 /Libraries/base_hardware/ 中。
上期讲到的outputStream和inputSream相关.h、.cpp文件放在 /Libraries/peripheral/ioBase/
headfile.h是C语言接口层头文件包含文件,里面全部是 #include"my_xxx.h",各种自己建立一个包含一下头文件就好了,没啥技术含量就不发了 ∪・ω・∪
本期文件附带的所有代码放在 /Libraries/other_support/ 中。
关于我的项目文件夹的结构和Keil文件管理请参考之前的文章:从新建工程开始使用C++开发单片机(以STM32为例):二、工程模板
工程文件整理好后就可以开始下一步的移植工作了。

2.文件移植:
接下来的步骤需要搜寻许多藏的很深的文件,并对其进行修改。如果需要一步一步自己移植的小伙伴请仔细阅读下面的内容;如果想要直接抱走代码的伙伴,我也把修改后的代码放在了文章的最后边。
在这里插入图片描述
首先,找到Arduino下WString.h和WString.cpp文件,这两个文件都在Arduino安装目录下的 /hardware/arduino/avr/cores/ 文件夹下可以找到。
我们将这两个文件复制到项目文件夹下的 /Libraries/other_support/ 中:
在这里插入图片描述
移动进去后,将WString.h中不相关的头文件去掉:
在这里插入图片描述
接着保存文件后,再Keil中尝试编译。编译过后,我们发现Keil报错输出了很多 “ultoa” is undefined 这类的错误:
在这里插入图片描述
这些 undefined 的函数是stdlib中的函数,而Keil的stdlib进行了删减,所有没有定义这些函数。如果在VSCode中,通过函数查找函数声明就可以在完整的stdlib.h中找到这些函数的声明。不过这对我们的移植工作没有帮助。
而在ESP8266和ESP32的Libraries,我们可以找到这样两个文件:stdlib_noniso.h和stdlib_noniso.c,乐鑫对他们的ESP芯片重写了那些缺少的函数,正好我们可以搬过来使用。这两个文件在 C:\Users\你的用户名\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6(或是其他版本)\cores\esp32 中可以找到。
这样所有需要的文件我们都有了,将他们都放在 /Libraries/other_support/ 中后,在 WString.cpp 中包含 stdlib_noniso.h 重新尝试编译。
PS:考虑到有的小伙伴可能没有安装Aduino 或没有安装Arduinp ESP32/8266的开发环境,我会将修改好后的文件放在文章下边。

编译之后,我们还会发现,报出了许多 xxx_P 未定义的错误,这些xxx_P的定义就在我们之前去掉的 <avr/pgmspace.h>中,我们可以在Arduino安装目录下的 \hardware\tools\avr\avr\include\avr 中找到这个文件。因为这个文件包含了很多Arduino AVR单片机很多底层的东西,所以我们不会移植这些文件,只是找到相应的宏定义,将报错的部分一一修改回去就可以了:
strcpy_P 改为 strcpy
strlen_P 改为 strlen
PGM_P 改为 const char *

再次编译过后,之剩只一个错误:Error: L6218E: Undefined symbol utoa (referred from wstring.o).
查看了stdlib_noniso.h和stdlib_noniso.c后会发现,utoa声明在了stdlib_noniso.h中,而在stdlib_noniso.c中没有进行定义。所以我们要在stdlib_noniso.c中添加utoa函数:

char *utoa(unsigned int val, char *s, int radix)
{return ultoa(val, s, radix);
}

因为val时unsigned int类型,而ultoa的第一个参数时unsigned long 类型,所以将val传给ultoa不会因为强制类型转换而值溢出。
最后再进行一次编译,发现已经 0 Error(s) 0 Waring(s) 了!到此为止,我们的移植就算是完成了。最后让我们来测试一下效果,
测试代码用的还是开头WString简单介绍中的代码

#include "User.h"
HardwareUART Serial(UART_1);
int main()
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);systick_init();adc_init();/********************************************************************/Serial.begin(115200);String str1 = "hello ", str2 = "world";String str = str1 + str2;Serial.print("str=str1+str2=");Serial.println(str);String str3 = "hello ";if (str3 == str1){Serial.println("str3==str1");}int a = 12345;String str4 = "a=";Serial.println(str4 + a);String str5 = "54321";a = str5.toInt();Serial.println(a);/********************************************************************/while (1){}
}

在这里插入图片描述
和前面的输出一模一样呢!
请添加图片描述
3.关于代码版权的问题:
有的伙伴可能会担心搬运这么多代码,会不会收到律师函(划掉)?对于这个问题,大家可以放心地去学习和使用,本文所移植的所有文件都是允许修改和传播的。大家再使用的时候,保留源文件的版权声明就好了!
附:相应文件版权声明:

/*stdlib_noniso.h - nonstandard (but usefull) conversion functionsCopyright (c) 2014 Ivan Grokhotkov. All rights reserved.This library is free software; you can redistribute it and/ormodify it under the terms of the GNU Lesser General PublicLicense as published by the Free Software Foundation; eitherversion 2.1 of the License, or (at your option) any later version.This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNULesser General Public License for more details.You should have received a copy of the GNU Lesser General PublicLicense along with this library; if not, write to the Free SoftwareFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*//*WString.h - String library for Wiring & Arduino...mostly rewritten by Paul Stoffregen...Copyright (c) 2009-10 Hernando Barragan.  All right reserved.Copyright 2011, Paul Stoffregen, paul@pjrc.comThis library is free software; you can redistribute it and/ormodify it under the terms of the GNU Lesser General PublicLicense as published by the Free Software Foundation; eitherversion 2.1 of the License, or (at your option) any later version.This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNULesser General Public License for more details.You should have received a copy of the GNU Lesser General PublicLicense along with this library; if not, write to the Free SoftwareFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

四、总结

在移植WString前,我也自己写过一个简单的String类并在项目中使用过,但用起来还是不如WString舒服。移植过程中遇到的许多困难在上面的步骤中都有展现过,虽然移植的过程看起来就是复制一下文件,修改一些代码就可以,但移植之前的准备工作中花了不少的精力去研究Arduino的继承结构,才能和自己的程序有比较好的兼容性。在上一篇文章和这篇文章中已经大量地使用了HardwareUART类来做数据的输出,有了String类地支持,我相信很多小伙伴已经可以在这基础上搓出一个自己的串口类。后面的文章我将会对HardwareUART的功能和设计进行解释。欢迎大家关注我哦~

本期表情包赞助:鹅厂QQ聊天框:
在这里插入图片描述

附:代码

/*file: stdlib_noniso.h*/
/*stdlib_noniso.h - nonstandard (but usefull) conversion functionsCopyright (c) 2014 Ivan Grokhotkov. All rights reserved.This library is free software; you can redistribute it and/ormodify it under the terms of the GNU Lesser General PublicLicense as published by the Free Software Foundation; eitherversion 2.1 of the License, or (at your option) any later version.This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNULesser General Public License for more details.You should have received a copy of the GNU Lesser General PublicLicense along with this library; if not, write to the Free SoftwareFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*//*修改&移植 龚为玮 2021年12月*/#ifndef STDLIB_NONISO_H
#define STDLIB_NONISO_H#ifdef __cplusplus
extern "C" {
#endifint atoi(const char *s);long atol(const char* s);double atof(const char* s);char* itoa (int val, char *s, int radix);char* ltoa (long val, char *s, int radix);char* utoa (unsigned int val, char *s, int radix);char* ultoa (unsigned long val, char *s, int radix);char* dtostrf (double val, signed char width, unsigned char prec, char *s);#ifdef __cplusplus
} // extern "C"
#endif#endif
/*file: stdlib_noniso.c*/
/*core_esp8266_noniso.c - nonstandard (but usefull) conversion functionsCopyright (c) 2014 Ivan Grokhotkov. All rights reserved.This file is part of the esp8266 core for Arduino environment.This library is free software; you can redistribute it and/ormodify it under the terms of the GNU Lesser General PublicLicense as published by the Free Software Foundation; eitherversion 2.1 of the License, or (at your option) any later version.This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNULesser General Public License for more details.You should have received a copy of the GNU Lesser General PublicLicense along with this library; if not, write to the Free SoftwareFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USAModified 03 April 2015 by Markus Sattler*//*修改&移植 龚为玮 2021年12月*/#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <math.h>
#include "stdlib_noniso.h"void reverse(char *begin, char *end)
{char *is = begin;char *ie = end - 1;while (is < ie){char tmp = *ie;*ie = *is;*is = tmp;++is;--ie;}
}char *ltoa(long value, char *result, int base)
{if (base < 2 || base > 16){*result = 0;return result;}char *out = result;long quotient = abs(value);do{const long tmp = quotient / base;*out = "0123456789abcdef"[quotient - (tmp * base)];++out;quotient = tmp;} while (quotient);// Apply negative signif (value < 0)*out++ = '-';reverse(result, out);*out = 0;return result;
}char *ultoa(unsigned long value, char *result, int base)
{if (base < 2 || base > 16){*result = 0;return result;}char *out = result;unsigned long quotient = value;do{const unsigned long tmp = quotient / base;*out = "0123456789abcdef"[quotient - (tmp * base)];++out;quotient = tmp;} while (quotient);reverse(result, out);*out = 0;return result;
}char *dtostrf(double number, signed char width, unsigned char prec, char *s)
{bool negative = false;if (isnan(number)){strcpy(s, "nan");return s;}if (isinf(number)){strcpy(s, "inf");return s;}char *out = s;int fillme = width; // how many cells to fill for the integer partif (prec > 0){fillme -= (prec + 1);}// Handle negative numbersif (number < 0.0){negative = true;fillme--;number = -number;}// Round correctly so that print(1.999, 2) prints as "2.00"// I optimized out most of the divisionsdouble rounding = 2.0;for (uint8_t i = 0; i < prec; ++i)rounding *= 10.0;rounding = 1.0 / rounding;number += rounding;// Figure out how big our number really isdouble tenpow = 1.0;int digitcount = 1;while (number >= 10.0 * tenpow){tenpow *= 10.0;digitcount++;}number /= tenpow;fillme -= digitcount;// Pad unused cells with spaceswhile (fillme-- > 0){*out++ = ' ';}// Handle negative signif (negative)*out++ = '-';// Print the digits, and if necessary, the decimal pointdigitcount += prec;int8_t digit = 0;while (digitcount-- > 0){digit = (int8_t)number;if (digit > 9)digit = 9; // insurance*out++ = (char)('0' | digit);if ((digitcount == prec) && (prec > 0)){*out++ = '.';}number -= digit;number *= 10.0;}// make sure the string is terminated*out = 0;return s;
}char *itoa(int val, char *s, int radix)
{return ltoa(val, s, radix);
}char *utoa(unsigned int val, char *s, int radix)
{return ultoa(val, s, radix);
}
/*file:  WString.h*/
/*WString.h - String library for Wiring & Arduino...mostly rewritten by Paul Stoffregen...Copyright (c) 2009-10 Hernando Barragan.  All right reserved.Copyright 2011, Paul Stoffregen, paul@pjrc.comThis library is free software; you can redistribute it and/ormodify it under the terms of the GNU Lesser General PublicLicense as published by the Free Software Foundation; eitherversion 2.1 of the License, or (at your option) any later version.This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNULesser General Public License for more details.You should have received a copy of the GNU Lesser General PublicLicense along with this library; if not, write to the Free SoftwareFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*//*修改&移植 龚为玮 2021年12月*/#ifndef String_class_h
#define String_class_h
#ifdef __cplusplus#include <stdlib.h>
#include <string.h>
#include <ctype.h>
//#include <avr/pgmspace.h>// When compiling programs with this class, the following gcc parameters
// dramatically increase performance and memory (RAM) efficiency, typically
// with little or no increase in code size.
//     -felide-constructors
//     -std=c++0xclass __FlashStringHelper;
#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))// An inherited class for holding the result of a concatenation.  These
// result objects are assumed to be writable by subsequent concatenations.
class StringSumHelper;// The string class
class String
{// use a function pointer to allow for "if (s)" without the// complications of an operator bool(). for more information, see:// http://www.artima.com/cppsource/safebool.htmltypedef void (String::*StringIfHelperType)() const;void StringIfHelper() const {}public:// constructors// creates a copy of the initial value.// if the initial value is null or invalid, or if memory allocation// fails, the string will be marked as invalid (i.e. "if (s)" will// be false).String(const char *cstr = "");String(const String &str);String(const __FlashStringHelper *str);#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)String(String &&rval);String(StringSumHelper &&rval);#endifexplicit 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);~String(void);// memory management// return true on success, false on failure (in which case, the string// is left unchanged).  reserve(0), if successful, will validate an// invalid string (i.e., "if (s)" will be true afterwards)unsigned char reserve(unsigned int size);inline unsigned int length(void) const {return len;}// creates a copy of the assigned value.  if the value is null or// invalid, or if the memory allocation fails, the string will be// marked as invalid ("if (s)" will be false).String & operator = (const String &rhs);String & operator = (const char *cstr);String & operator = (const __FlashStringHelper *str);#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)String & operator = (String &&rval);String & operator = (StringSumHelper &&rval);#endif// concatenate (works w/ built-in types)// returns true on success, false on failure (in which case, the string// is left unchanged).  if the argument is null or invalid, the// concatenation is considered unsucessful.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);// if there's not enough memory for the concatenated value, the string// will be left unchanged (but this isn't signalled in any way)String & operator += (const String &rhs)	{concat(rhs); return (*this);}String & operator += (const char *cstr)		{concat(cstr); return (*this);}String & operator += (char c)			{concat(c); return (*this);}String & operator += (unsigned char num)		{concat(num); return (*this);}String & operator += (int num)			{concat(num); return (*this);}String & operator += (unsigned int num)		{concat(num); return (*this);}String & operator += (long num)			{concat(num); return (*this);}String & operator += (unsigned long num)	{concat(num); return (*this);}String & operator += (float num)		{concat(num); return (*this);}String & operator += (double num)		{concat(num); return (*this);}String & operator += (const __FlashStringHelper *str){concat(str); return (*this);}friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs);friend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr);friend StringSumHelper & operator + (const StringSumHelper &lhs, char c);friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num);friend StringSumHelper & operator + (const StringSumHelper &lhs, int num);friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num);friend StringSumHelper & operator + (const StringSumHelper &lhs, long num);friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num);friend StringSumHelper & operator + (const StringSumHelper &lhs, float num);friend StringSumHelper & operator + (const StringSumHelper &lhs, double num);friend StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs);// comparison (only works w/ Strings and "strings")operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; }int compareTo(const String &s) const;unsigned char equals(const String &s) const;unsigned char equals(const char *cstr) const;unsigned char operator == (const String &rhs) const {return equals(rhs);}unsigned char operator == (const char *cstr) const {return equals(cstr);}unsigned char operator != (const String &rhs) const {return !equals(rhs);}unsigned char operator != (const char *cstr) const {return !equals(cstr);}unsigned char operator <  (const String &rhs) const;unsigned char operator >  (const String &rhs) const;unsigned char operator <= (const String &rhs) const;unsigned char operator >= (const String &rhs) const;unsigned char equalsIgnoreCase(const String &s) const;unsigned char startsWith( const String &prefix) const;unsigned char startsWith(const String &prefix, unsigned int offset) const;unsigned char endsWith(const String &suffix) const;// character acccesschar charAt(unsigned int index) const;void setCharAt(unsigned int index, char c);char operator [] (unsigned int index) const;char& operator [] (unsigned int index);void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const;void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const{ getBytes((unsigned char *)buf, bufsize, index); }const char* c_str() const { return buffer; }char* begin() { return buffer; }char* end() { return buffer + length(); }const char* begin() const { return c_str(); }const char* end() const { return c_str() + length(); }// searchint indexOf( char ch ) const;int indexOf( char ch, unsigned int fromIndex ) const;int indexOf( const String &str ) const;int indexOf( const String &str, unsigned int fromIndex ) const;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 { return substring(beginIndex, len); };String substring( unsigned int beginIndex, unsigned int endIndex ) const;// modificationvoid replace(char find, char replace);void replace(const String& find, const String& replace);void remove(unsigned int index);void remove(unsigned int index, unsigned int count);void toLowerCase(void);void toUpperCase(void);void trim(void);// parsing/conversionlong toInt(void) const;float toFloat(void) const;double toDouble(void) const;protected:char *buffer;	        // the actual char arrayunsigned int capacity;  // the array length minus one (for the '\0')unsigned int len;       // the String length (not counting the '\0')
protected:void init(void);void invalidate(void);unsigned char changeBuffer(unsigned int maxStrLen);unsigned char concat(const char *cstr, unsigned int length);// copy and moveString & copy(const char *cstr, unsigned int length);String & copy(const __FlashStringHelper *pstr, unsigned int length);#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)void move(String &rhs);#endif
};class StringSumHelper : public String
{
public:StringSumHelper(const String &s) : String(s) {}StringSumHelper(const char *p) : String(p) {}StringSumHelper(char c) : String(c) {}StringSumHelper(unsigned char num) : String(num) {}StringSumHelper(int num) : String(num) {}StringSumHelper(unsigned int num) : String(num) {}StringSumHelper(long num) : String(num) {}StringSumHelper(unsigned long num) : String(num) {}StringSumHelper(float num) : String(num) {}StringSumHelper(double num) : String(num) {}
};#endif  // __cplusplus
#endif  // String_class_h
/*file:  WString.cpp*/
/*WString.cpp - String library for Wiring & Arduino...mostly rewritten by Paul Stoffregen...Copyright (c) 2009-10 Hernando Barragan.  All rights reserved.Copyright 2011, Paul Stoffregen, paul@pjrc.comThis library is free software; you can redistribute it and/ormodify it under the terms of the GNU Lesser General PublicLicense as published by the Free Software Foundation; eitherversion 2.1 of the License, or (at your option) any later version.This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNULesser General Public License for more details.You should have received a copy of the GNU Lesser General PublicLicense along with this library; if not, write to the Free SoftwareFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*//*修改&移植 龚为玮 2021年12月*/#include "WString.h"
#include "stdlib_noniso.h"/*********************************************/
/*  Constructors                             */
/*********************************************/String::String(const char *cstr)
{init();if (cstr) copy(cstr, strlen(cstr));
}String::String(const String &value)
{init();*this = value;
}String::String(const __FlashStringHelper *pstr)
{init();*this = pstr;
}#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
String::String(String &&rval)
{init();move(rval);
}
String::String(StringSumHelper &&rval)
{init();move(rval);
}
#endifString::String(char c)
{init();char buf[2];buf[0] = c;buf[1] = 0;*this = buf;
}String::String(unsigned char value, unsigned char base)
{init();char buf[1 + 8 * sizeof(unsigned char)];utoa(value, buf, base);*this = buf;
}String::String(int value, unsigned char base)
{init();char buf[2 + 8 * sizeof(int)];itoa(value, buf, base);*this = buf;
}String::String(unsigned int value, unsigned char base)
{init();char buf[1 + 8 * sizeof(unsigned int)];utoa(value, buf, base);*this = buf;
}String::String(long value, unsigned char base)
{init();char buf[2 + 8 * sizeof(long)];ltoa(value, buf, base);*this = buf;
}String::String(unsigned long value, unsigned char base)
{init();char buf[1 + 8 * sizeof(unsigned long)];ultoa(value, buf, base);*this = buf;
}String::String(float value, unsigned char decimalPlaces)
{init();char buf[33];*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
}String::String(double value, unsigned char decimalPlaces)
{init();char buf[33];*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
}String::~String()
{if (buffer) free(buffer);
}/*********************************************/
/*  Memory Management                        */
/*********************************************/inline void String::init(void)
{buffer = NULL;capacity = 0;len = 0;
}void String::invalidate(void)
{if (buffer) free(buffer);buffer = NULL;capacity = len = 0;
}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;
}/*********************************************/
/*  Copy and Move                            */
/*********************************************/String & String::copy(const char *cstr, unsigned int length)
{if (!reserve(length)) {invalidate();return *this;}len = length;strcpy(buffer, cstr);return *this;
}String & String::copy(const __FlashStringHelper *pstr, unsigned int length)
{if (!reserve(length)) {invalidate();return *this;}len = length;strcpy(buffer, (const char *)pstr);return *this;
}#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
void String::move(String &rhs)
{if (buffer) {if (rhs && capacity >= rhs.len) {strcpy(buffer, rhs.buffer);len = rhs.len;rhs.len = 0;return;} else {free(buffer);}}buffer = rhs.buffer;capacity = rhs.capacity;len = rhs.len;rhs.buffer = NULL;rhs.capacity = 0;rhs.len = 0;
}
#endifString & String::operator = (const String &rhs)
{if (this == &rhs) return *this;if (rhs.buffer) copy(rhs.buffer, rhs.len);else invalidate();return *this;
}#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
String & String::operator = (String &&rval)
{if (this != &rval) move(rval);return *this;
}String & String::operator = (StringSumHelper &&rval)
{if (this != &rval) move(rval);return *this;
}
#endifString & String::operator = (const char *cstr)
{if (cstr) copy(cstr, strlen(cstr));else invalidate();return *this;
}String & String::operator = (const __FlashStringHelper *pstr)
{if (pstr) copy(pstr, strlen((const char *)pstr));else invalidate();return *this;
}/*********************************************/
/*  concat                                   */
/*********************************************/unsigned char String::concat(const String &s)
{return concat(s.buffer, s.len);
}unsigned char String::concat(const char *cstr, unsigned int length)
{unsigned int newlen = len + length;if (!cstr) return 0;if (length == 0) return 1;if (!reserve(newlen)) return 0;strcpy(buffer + len, cstr);len = newlen;return 1;
}unsigned char String::concat(const char *cstr)
{if (!cstr) return 0;return concat(cstr, strlen(cstr));
}unsigned char String::concat(char c)
{char buf[2];buf[0] = c;buf[1] = 0;return concat(buf, 1);
}unsigned char String::concat(unsigned char num)
{char buf[1 + 3 * sizeof(unsigned char)];itoa(num, buf, 10);return concat(buf, strlen(buf));
}unsigned char String::concat(int num)
{char buf[2 + 3 * sizeof(int)];itoa(num, buf, 10);return concat(buf, strlen(buf));
}unsigned char String::concat(unsigned int num)
{char buf[1 + 3 * sizeof(unsigned int)];utoa(num, buf, 10);return concat(buf, strlen(buf));
}unsigned char String::concat(long num)
{char buf[2 + 3 * sizeof(long)];ltoa(num, buf, 10);return concat(buf, strlen(buf));
}unsigned char String::concat(unsigned long num)
{char buf[1 + 3 * sizeof(unsigned long)];ultoa(num, buf, 10);return concat(buf, strlen(buf));
}unsigned char String::concat(float num)
{char buf[20];char* string = dtostrf(num, 4, 2, buf);return concat(string, strlen(string));
}unsigned char String::concat(double num)
{char buf[20];char* string = dtostrf(num, 4, 2, buf);return concat(string, strlen(string));
}unsigned char String::concat(const __FlashStringHelper * str)
{if (!str) return 0;int length = strlen((const char *) str);if (length == 0) return 1;unsigned int newlen = len + length;if (!reserve(newlen)) return 0;strcpy(buffer + len, (const char *) str);len = newlen;return 1;
}/*********************************************/
/*  Concatenate                              */
/*********************************************/StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs)
{StringSumHelper &a = const_cast<StringSumHelper&>(lhs);if (!a.concat(rhs.buffer, rhs.len)) a.invalidate();return a;
}StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr)
{StringSumHelper &a = const_cast<StringSumHelper&>(lhs);if (!cstr || !a.concat(cstr, strlen(cstr))) a.invalidate();return a;
}StringSumHelper & operator + (const StringSumHelper &lhs, char c)
{StringSumHelper &a = const_cast<StringSumHelper&>(lhs);if (!a.concat(c)) a.invalidate();return a;
}StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num)
{StringSumHelper &a = const_cast<StringSumHelper&>(lhs);if (!a.concat(num)) a.invalidate();return a;
}StringSumHelper & operator + (const StringSumHelper &lhs, int num)
{StringSumHelper &a = const_cast<StringSumHelper&>(lhs);if (!a.concat(num)) a.invalidate();return a;
}StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num)
{StringSumHelper &a = const_cast<StringSumHelper&>(lhs);if (!a.concat(num)) a.invalidate();return a;
}StringSumHelper & operator + (const StringSumHelper &lhs, long num)
{StringSumHelper &a = const_cast<StringSumHelper&>(lhs);if (!a.concat(num)) a.invalidate();return a;
}StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num)
{StringSumHelper &a = const_cast<StringSumHelper&>(lhs);if (!a.concat(num)) a.invalidate();return a;
}StringSumHelper & operator + (const StringSumHelper &lhs, float num)
{StringSumHelper &a = const_cast<StringSumHelper&>(lhs);if (!a.concat(num)) a.invalidate();return a;
}StringSumHelper & operator + (const StringSumHelper &lhs, double num)
{StringSumHelper &a = const_cast<StringSumHelper&>(lhs);if (!a.concat(num)) a.invalidate();return a;
}StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs)
{StringSumHelper &a = const_cast<StringSumHelper&>(lhs);if (!a.concat(rhs))	a.invalidate();return a;
}/*********************************************/
/*  Comparison                               */
/*********************************************/int String::compareTo(const String &s) const
{if (!buffer || !s.buffer) {if (s.buffer && s.len > 0) return 0 - *(unsigned char *)s.buffer;if (buffer && len > 0) return *(unsigned char *)buffer;return 0;}return strcmp(buffer, s.buffer);
}unsigned char String::equals(const String &s2) const
{return (len == s2.len && compareTo(s2) == 0);
}unsigned char String::equals(const char *cstr) const
{if (len == 0) return (cstr == NULL || *cstr == 0);if (cstr == NULL) return buffer[0] == 0;return strcmp(buffer, cstr) == 0;
}unsigned char String::operator<(const String &rhs) const
{return compareTo(rhs) < 0;
}unsigned char String::operator>(const String &rhs) const
{return compareTo(rhs) > 0;
}unsigned char String::operator<=(const String &rhs) const
{return compareTo(rhs) <= 0;
}unsigned char String::operator>=(const String &rhs) const
{return compareTo(rhs) >= 0;
}unsigned char String::equalsIgnoreCase( const String &s2 ) const
{if (this == &s2) return 1;if (len != s2.len) return 0;if (len == 0) return 1;const char *p1 = buffer;const char *p2 = s2.buffer;while (*p1) {if (tolower(*p1++) != tolower(*p2++)) return 0;} return 1;
}unsigned char String::startsWith( const String &s2 ) const
{if (len < s2.len) return 0;return startsWith(s2, 0);
}unsigned char String::startsWith( const String &s2, unsigned int offset ) const
{if (offset > len - s2.len || !buffer || !s2.buffer) return 0;return strncmp( &buffer[offset], s2.buffer, s2.len ) == 0;
}unsigned char String::endsWith( const String &s2 ) const
{if ( len < s2.len || !buffer || !s2.buffer) return 0;return strcmp(&buffer[len - s2.len], s2.buffer) == 0;
}/*********************************************/
/*  Character Access                         */
/*********************************************/char String::charAt(unsigned int loc) const
{return operator[](loc);
}void String::setCharAt(unsigned int loc, char c) 
{if (loc < len) buffer[loc] = c;
}char & String::operator[](unsigned int index)
{static char dummy_writable_char;if (index >= len || !buffer) {dummy_writable_char = 0;return dummy_writable_char;}return buffer[index];
}char String::operator[]( unsigned int index ) const
{if (index >= len || !buffer) return 0;return buffer[index];
}void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index) const
{if (!bufsize || !buf) return;if (index >= len) {buf[0] = 0;return;}unsigned int n = bufsize - 1;if (n > len - index) n = len - index;strncpy((char *)buf, buffer + index, n);buf[n] = 0;
}/*********************************************/
/*  Search                                   */
/*********************************************/int String::indexOf(char c) const
{return indexOf(c, 0);
}int String::indexOf( char ch, unsigned int fromIndex ) const
{if (fromIndex >= len) return -1;const char* temp = strchr(buffer + fromIndex, ch);if (temp == NULL) return -1;return temp - buffer;
}int String::indexOf(const String &s2) const
{return indexOf(s2, 0);
}int String::indexOf(const String &s2, unsigned int fromIndex) const
{if (fromIndex >= len) return -1;const char *found = strstr(buffer + fromIndex, s2.buffer);if (found == NULL) return -1;return found - buffer;
}int String::lastIndexOf( char theChar ) const
{return lastIndexOf(theChar, len - 1);
}int String::lastIndexOf(char ch, unsigned int fromIndex) const
{if (fromIndex >= len) return -1;char tempchar = buffer[fromIndex + 1];buffer[fromIndex + 1] = '\0';char* temp = strrchr( buffer, ch );buffer[fromIndex + 1] = tempchar;if (temp == NULL) return -1;return temp - buffer;
}int String::lastIndexOf(const String &s2) const
{return lastIndexOf(s2, len - s2.len);
}int String::lastIndexOf(const String &s2, unsigned int fromIndex) const
{if (s2.len == 0 || len == 0 || s2.len > len) return -1;if (fromIndex >= len) fromIndex = len - 1;int found = -1;for (char *p = buffer; p <= buffer + fromIndex; p++) {p = strstr(p, s2.buffer);if (!p) break;if ((unsigned int)(p - buffer) <= fromIndex) found = p - buffer;}return found;
}String String::substring(unsigned int left, unsigned int right) const
{if (left > right) {unsigned int temp = right;right = left;left = temp;}String out;if (left >= len) return out;if (right > len) right = len;char temp = buffer[right];  // save the replaced characterbuffer[right] = '\0';	out = buffer + left;  // pointer arithmeticbuffer[right] = temp;  //restore characterreturn out;
}/*********************************************/
/*  Modification                             */
/*********************************************/void String::replace(char find, char replace)
{if (!buffer) return;for (char *p = buffer; *p; p++) {if (*p == find) *p = replace;}
}void String::replace(const String& find, const String& replace)
{if (len == 0 || find.len == 0) return;int diff = replace.len - find.len;char *readFrom = buffer;char *foundAt;if (diff == 0) {while ((foundAt = strstr(readFrom, find.buffer)) != NULL) {memcpy(foundAt, replace.buffer, replace.len);readFrom = foundAt + replace.len;}} else if (diff < 0) {char *writeTo = buffer;while ((foundAt = strstr(readFrom, find.buffer)) != NULL) {unsigned int n = foundAt - readFrom;memcpy(writeTo, readFrom, n);writeTo += n;memcpy(writeTo, replace.buffer, replace.len);writeTo += replace.len;readFrom = foundAt + find.len;len += diff;}strcpy(writeTo, readFrom);} else {unsigned int size = len; // compute size needed for resultwhile ((foundAt = strstr(readFrom, find.buffer)) != NULL) {readFrom = foundAt + find.len;size += diff;}if (size == len) return;if (size > capacity && !changeBuffer(size)) return; // XXX: tell user!int index = len - 1;while (index >= 0 && (index = lastIndexOf(find, index)) >= 0) {readFrom = buffer + index + find.len;memmove(readFrom + diff, readFrom, len - (readFrom - buffer));len += diff;buffer[len] = 0;memcpy(buffer + index, replace.buffer, replace.len);index--;}}
}void String::remove(unsigned int index){// Pass the biggest integer as the count. The remove method// below will take care of truncating it at the end of the// string.remove(index, (unsigned int)-1);
}void String::remove(unsigned int index, unsigned int count){if (index >= len) { return; }if (count <= 0) { return; }if (count > len - index) { count = len - index; }char *writeTo = buffer + index;len = len - count;strncpy(writeTo, buffer + index + count,len - index);buffer[len] = 0;
}void String::toLowerCase(void)
{if (!buffer) return;for (char *p = buffer; *p; p++) {*p = tolower(*p);}
}void String::toUpperCase(void)
{if (!buffer) return;for (char *p = buffer; *p; p++) {*p = toupper(*p);}
}void String::trim(void)
{if (!buffer || len == 0) return;char *begin = buffer;while (isspace(*begin)) begin++;char *end = buffer + len - 1;while (isspace(*end) && end >= begin) end--;len = end + 1 - begin;if (begin > buffer) memcpy(buffer, begin, len);buffer[len] = 0;
}/*********************************************/
/*  Parsing / Conversion                     */
/*********************************************/long String::toInt(void) const
{if (buffer) return atol(buffer);return 0;
}float String::toFloat(void) const
{return float(toDouble());
}double String::toDouble(void) const
{if (buffer) return atof(buffer);return 0;
}

http://chatgpt.dhexx.cn/article/g7kqIH4g.shtml

相关文章

0005:Qt常用类 - QDateTime

Qt常用类 - QDateTime 1 开发环境 在介绍内容之前&#xff0c;先说明一下开发环境&#xff0c;如下图&#xff1a; Qt版本&#xff1a;Qt5.3.2&#xff1b; Qt开发工具&#xff1a;Qt Creater 3.2.1&#xff1b; Qt构建工具&#xff1a;Desktop Qt 5.3 MinGW 32bit&#xff…

QDateTime的11种显示方式

QDateTime datetime QDateTime::currentDateTime(); datetime.toString(“hh:mm:ss\nyyyy/MM/dd”); datetime.toString(“hh:mm:ss ap\nyyyy/MM/dd”); datetime.toString(“hh:mm:ss\nyyyy-MM-dd”); datetime.toString(“hh:mm:ss ap\nyyyy-MM-dd”); datetime.to…

70 QDateTime时间戳转换有误

1 前言 在开发工具中需要用时间戳转换成格式化时间来显示&#xff0c;但引用QT中自带的时间类QDateTime转换时&#xff0c;发现转换时间有误问题&#xff0c;转换的结果时分秒是正确的&#xff0c;但月份确实错误的。因此在未深入研究qt实现情况下&#xff0c;需要得到正确的格…

QDateTime类的部分函数使用解析

QDateTime类提供了日期和时间功能。 QDateTime对象包含一个日历日期和一个时钟时间&#xff08;一个“日期时间”&#xff09;。它是QDate和QTime两个类的组合。它可以从系统时钟中读取当前日期时间。它提供比较日期时间和操作日期时间的函数&#xff0c;比如加上一定数量的秒…

QDateTime时间相减

qDebug()<<"span"<<QDateTime::fromMSecsSinceEpoch(QDateTime::currentDateTime().toMSecsSinceEpoch() - time.toMSecsSinceEpoch()).toUTC().toString("hh:mm:ss"); 1、使用 QDateTime::toMSecsSinceEpoch 计算时间差&#xff1b; 2、使用…

小心 QDateTime

QDateTime 时间跳变问题接收服务端时间问题 时间跳变问题 QDateTime的具体用法可以在Qt creator 鼠标双击选中&#xff0c;按 F1 查看它的文档, Qt 的文档还是不错的. 我们有时会用下面的代码来做等待, 在笔者使用过程中发现 //等待QDateTime n QDateTime::currentDateTime(…

QDateTime

一、描述 QDateTime 对象对日历日期和时钟时间进行编码。它结合了 QDate 和 QTime 类的特性。它可以从系统时钟中读取当前日期时间。它提供了用于比较日期时间和通过添加秒数、天数、月数或年数来操作日期时间的函数。 二、成员函数 1、QString toString(const QString &…

QDateTime、QTime获取当前时间

1、引用头文件 #include #include 2、显示当前时间 ui->label->setText(“QDateTime:\nCurrent Time is:” QDateTime::currentDateTime().toString(“yyyy-MM-dd hh:mm:ss ddd”)); ui->label->setText(ui->label->text() "\n\nQTime:\nHour mi…

通过图像修复的视觉提示

Visual Prompting via Image Inpainting 目录 总结 一、Introduction 二、Visual Prompting via Image Inpainting 1. Inpainting using MAE-VQGAN 2. Prompting Inpainting Models 3. The Computer Vision Figures Dataset 三、Experiments and Results 四、Discussio…

图像修复必读的10篇论文

点击上方“AI公园”&#xff0c;关注公众号&#xff0c;选择加“星标“或“置顶” 因公众号更改了推送规则&#xff0c;记得读完点“在看”~下次AI公园的新文章就能及时出现在您的订阅列表中 作者&#xff1a;Chu-Tak Li 编译&#xff1a;ronghuaiyang 导读 这10篇文章给出了图…

【图像修复】论文阅读笔记 ----- 《Image inpainting based on deep learning: A review》

文章目录 原文下载地址概述**单阶段修复****单结果修复****多元修复方法** **渐进图像修复**低分辨率图像修复高分辨率图像修复 基于先验知识的修复轮廓边缘引导图像修复生成性先验引导图像修复 用于图像修复的数据集**不规则掩模数据集&#xff1a;****图像修复数据集&#xf…

毕业设计之 - 基于深度学的图像修复 图像补全

1 前言 Hi&#xff0c;大家好&#xff0c;这里是丹成学长&#xff0c;今天向大家介绍 基于深度学的图像修复 图像补全 大家可用于 毕业设计 2 什么是图像内容填充修复 内容识别填充(译注: Content-aware fill ,是 photoshop 的一个功能)是一个强大的工具&#xff0c;设计师…

基于GAN的图像修复--论文笔记

文献下载看下载处或评论链接 /1 Region Normalization for Image Inpainting 主要内容&#xff1a;将损坏的图像输入到神经网络中可能会产生问题&#xff0c;例如无效像素的卷积、归一化的均值和方差。但是&#xff0c;当前方法无法解决网络中的均值和方差漂移问题。当前方…

图像修复文章汇总

图像修复技术的研究是计算机视觉以及计算机图形学的一个具有重大意义的研究课题。对于带有损失区域的图像&#xff0c;由于我们并不知道原本图像的具体形式&#xff0c;我们只能类似于“凭空捏造”一些像素去填补这种缺失。正因如此&#xff0c;图像修复实际是根据人类自己的视…

图像算法原理与实践——图像修复之 全变分模型

在图像算法的高层次处理中&#xff0c;有一类很典型的应用&#xff0c;就是图像修复算法。图像在采集、传输、预处理过程中&#xff0c;都可能会发生图像数据被修改、损失和缺失等问题&#xff08;例如&#xff1a;部分图像内容被污染、雾霾等&#xff09;&#xff0c;另外&…

图像修复序列——BSCB模型

1. 参考文献 2. BSCB模型代码 2.1 BSCB模型demo % demo_BSCB.m % Author: HSW % Date: 2015/3/25 % HARBIN INSTITUTE OF TECHNOLOGY % % set matlab close all; clear all; clc;options.null 0; % read image Img imread(Image\butterfly.bmp); Img imread(Image\peppers…

day29:图像修复

在实际应用 中&#xff0c; 图像常常会受到噪声的干扰&#xff0c;例如拍照时镜头上存在灰尘或者飞行的小动物。这些 干 扰会导 拍摄到的图像出现部分内容被遮挡 的情况.对于较为久远的图像&#xff0c;可能只有实体图像而没有数字存储形式的底板&#xff0c; 因此相片在保存和…

【图像修复】基于深度学习的图像修复算法的MATLAB仿真

1.软件版本 matlab2021a 2.本算法理论知识 在许多领域&#xff0c;人们对图像质量的要求都很高&#xff0c;如医学图像领域、卫星遥感领域等。随着信息时代的快速发展&#xff0c;低分辨率图像已经难以满足特定场景的需要。因此&#xff0c;低分辨率图像恢复与重建的研究逐渐…

【毕业设计】深度学习图像修复算法研究与实现 - python

文章目录 1 前言2 什么是图像内容填充修复3 原理分析3.1 第一步&#xff1a;将图像理解为一个概率分布的样本3.2 补全图像 3.3 快速生成假图像3.4 生成对抗网络(Generative Adversarial Net, GAN) 的架构3.5 使用G(z)生成伪图像 4 在Tensorflow上构建DCGANs5 最后 1 前言 &…

图像修复 图像补全_图像修复简介

图像修复 图像补全 In practical applications, images are often corroded by noise. These noises are dust or water droplets on the lens, or scratches from old photos, or the image is artificially painted or part of the image Itself has been damaged. 在实际应用…