Arduino 数据类型转换

使用过Python的数据类型后,会发现C/C++的数据类型比较单一。Arduino实际上是C++,除了基础数据类型,增加了String类。通过了解标准库和类的头文件,可以减少不必要的、重复的、琐碎的、易错的手工代码。除了Arduino,其他的GCC和嵌入式C语言中也可以参照执行。

IoT相关数据类型

  • byte, unsigned char
  • char
  • int, int and unsigned int
  • float
  • String,class of char array
  • struct

IoT需要解决的主要是采集、传输、判断、控制。传输通道上数据以二进制数据为主。

C语言设计中,二进制数据采用unsigned char[],使用简单。二进制处理采用struct结构体可以很好地解决固定长度的unsigned char[]。但是动态长度的传输协议的结构体往往需要包含额外的缓冲区指针。

C语言中,字符串采用char[],即字符数组来实现。但是无论是初始化、转换、处理起来,代码都很琐碎。所以ANSI标准的C语言标准库中提供了大量的面向字符以及字符串的函数。在Java/C++等OOP语言中,也都定义String类。注意,这些是类(class),而非数据类型(type)。

由于IoT引入了许多Web协议,而大多数Web协议如HTTP/FTP/Telnet都基于字符串。所以许多情况下,代码需要在这两种协议之间进行转换。所以unsigned char和char是最基础的数据类型。

unsigned char和char可以通过强制类型转换来实现。但是unsigned char[],char[],String三者之间却有着一定的差异,主要因为char[]/String定义的字符串结束符必须使用NULL,即\0来实现。在某些特殊情况下会因为两种数据类型长度不一致,或者缺乏NULL结束符导致程序跑飞。

String类

在Arduino的WString.h/WString.cpp中可以找到对应的String类定义。

inline void String::init(void) {
    buffer = NULL;
    capacity = 0;
    len = 0;
}

WString.cpp引用了stdlib_noiso.h这个头文件,也就是底层依然调用了libc来实现一些功能。在构建函数中,可以看到其调用utoa(),itoa(),ltoa()等stdlib.h中定义的函数。

类型转换

虽然C语言是理工科大学必修课程,但是在MCU级别使用C语言却是在工作中。从Keil的C51语言开始,因为资源受限,实际工程中很少使用标准库,一些小的常用函数都是自己写的,目的是通过不同模块的缓冲区复用(overlap)实现少占用RAM空间。而现在STM32/ESP8266的RAM都比之前8051 256B要多许多,使用标准库和类库以实现标准化开发,可以明显加快开发。

当然,不必将所有的库和类库都背下来,可以在使用中摸索出操作的常用函数,然后在标准库和类库中去寻找对应物。

  • String to char array
  • String to byte array
  • String to int
  • String to float

各种库

不同C编译器环境有着类似(ANSI C libc)但是有细微差异的库(glibc)。需要自行检索。

  • stdlib.h,libc的一部分,包含了部分str转其他类型的函数定义。
  • ctypes.h, libc的一部分,包含了字符char的函数定义。
  • string.h, libc的一部分,包含了大多数字符串操纵如复制、检索、比较等函数定义。
  • Wstring.h,Arduino自定义的String类,依赖于stdlib.h/string.h的函数。
  • Wcharater.h,Arduino定义的字符类型操作,如判断、转换。依赖于ctype.h的转换函数。
#include <stdlib.h>

// string to double or float
double atof(const char *s);
float atoff(const char *s);

// string to integer
int atoi(const char *s);    // = (int)strtol(s, NULL, 10);
long atol(const char *s);   // = strtol(s, NULL, 10);

// double or float to string
char *ecvt(double val, int chars, int *decpt, int *sgn);
char *ecvtf(float val, int chars, int *decpt, int *sgn);
char *fcvt(double val, int decimals, int *decpt, int *sgn);
char *fcvtf(float val, int decimals, int *decpt, int *sgn);

// format double or float as string
char *gcvt(double val, int precision, char* buf);
char *gcvtf(float val, int precision, char* buf);

// double or float to string
char *ecvtbuf(double val, int chars, int *decpt, int *sgn, char *buf);
char *ecvtfbuf(float val, int chars, int *decpt, int *sgn, char *buf);

// integer or unsigned int to string
char *itoa(int value, char *str, int base);
char *utoa(unsigned value, char *str, int base);

// string to double or float
double strtod(const char *restrict str, char **restrict tail);
float strtof(const char *restrict str, char **restrict tail);

// string to long or unsigned long
long strtol(const char *restrict s, char **restrict ptr, int base);
unsigned long strtoul(const char *restrict s, char **restrict ptr, int base);

// binary search
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));

#include <ctype.h>

int isalnum(int c); // is alphanumberic
int isalpha(int c); // is alphabetic
int isascii(int c); // is ASCII char
int isblank(int c); // 
int iscntrl(int c);
int isdigit(int c);
int islower(int c);
int isprint(int c); // is printable
int ispunct(int c); // punctuation
int isspace(int c); // is space
int isupper(int c);
int isxdigit(int c); // is hexdecimal digit
int toascii(int c); // force to ascii, by clearing MSB
int tolower(int c);
int toupper(int c);

#include <string.h>

int bcmp(const void *s1, const void *s2, size_t n); // = memcmp
int bcopy(const void *in, void *out, size_t n); // = memmove
void bzero(void *b, size_t length);
char *index(const char *string, int c);    // = strchr
void *memccpy(void *restrict out, const void *restrict in, int endchar, size_t n);
void *memchr(const void *src, int c, size_t length);
int memcmp(const void *s1, const void *s2, size_t n);
void *memcpy(void *restrict out, const void *restrict in, size_t n);
char *memmem(const void *s1, size_t l1, const void *s2, size_t l2);
void *memmove(void *dst, void *src, size_t length);
void *memrchr(const void *src, int c, size_t length);
void *memset(void *dst, int c, size_t length);
void *rawmemchr(const void *src, int c);
void *rindex(const char * string, int c);
char *strpcpy(char *restrict dst, const char *restrict src);
char *strncpy(char *restrict dst, const char *restrict src, size_t length);
int strcasecmp(const char *a, const char *b);
char *strcasestr(const char *s, const char *find);
char *strcat(char *restrict dst, const char *restrict src);
char *strchr(const char *string, int c);
char *strchrnul(const char *string, int c);
int strcmp(const char *a, const char *b);
char *strcpy(char *dst, char *src);
size_t strlen(const char *str);
char *strlwr(char *a);
int strncasecmp(const char *a, const char *b, size_t length);
char *strncat(char *restrict dst, const char *restrict src, size_t length);
int strncmp(const char *a, const char *b, size_t length);
char *strncpy(char *restrict dst, const char *restrict src, size_t length);
size_t strlen(const char *str, size_t length);
char *strpbrk(const char *s1, const char *s1);
char *strrchr(const char *string, int c);
char *strstr(const char *s1, const char *s2);
char *strtok(char *restrict source, const char *restrict delimiters);

仔细阅读Arduino的WString/WCharater的头文件,其底层依然是依赖于标准库libc。

其他操作

Python编写IoT应用时,有些特殊的操作,是没有C语言对应物的,都需要自己去编写。比如split()切割字符串等。

Web URLs

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容

  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom阅读 2,665评论 0 3
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,800评论 6 13
  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,674评论 0 38
  • 人类社会大部分东西,都是具有逻辑性的,要学会经常去思考背后的逻辑。这样做的一个好处便是,记忆会变得比较简单。比如公...
    中南偏南阅读 402评论 0 0
  • 我想象那是诗经中的第一个女人 在水的彼岸徜徉 可知道孤独也会消瘦 寂寞也能燃烧 在幽暗的光纤隧道 看作远景多么朦胧...
    微风LG阅读 196评论 0 0